From f324f9ee8af23cfd932d7c4e98fe581a0152700c Mon Sep 17 00:00:00 2001 From: Pramod Nuthakki Date: Wed, 3 Sep 2014 16:12:07 +0530 Subject: [PATCH 1/2] MIFOSX-1419 : moved capturing of rest frequency to product --- ..._moved_rest_frequency_to_product_level.sql | 9 ++ .../core/data/DataValidatorBuilder.java | 18 ++++ .../loanaccount/api/LoanApiConstants.java | 1 - .../loanaccount/api/LoansApiResource.java | 6 +- .../loanaccount/data/LoanAccountData.java | 55 +++-------- .../data/LoanInterestRecalculationData.java | 15 ++- .../portfolio/loanaccount/domain/Loan.java | 38 +++++-- .../LoanInterestRecalculationDetails.java | 63 ++++++++++-- .../domain/AbstractLoanScheduleGenerator.java | 11 +-- .../domain/LoanApplicationTerms.java | 27 +++-- ...ateLoanScheduleQueryFromApiJsonHelper.java | 2 +- ...anApplicationCommandFromApiJsonHelper.java | 31 +++--- ...WritePlatformServiceJpaRepositoryImpl.java | 76 +++++++------- .../loanaccount/service/LoanAssembler.java | 6 +- .../service/LoanReadPlatformServiceImpl.java | 15 +-- .../loanproduct/LoanProductConstants.java | 3 + .../api/LoanProductsApiResource.java | 8 +- .../loanproduct/data/LoanProductData.java | 30 +++++- .../LoanProductInterestRecalculationData.java | 29 +++++- .../loanproduct/domain/LoanProduct.java | 19 +--- ...anProductInterestRecalculationDetails.java | 95 +++++++++++++++++- .../domain/RecalculationFrequencyType.java | 21 +++- .../LoanProductDataValidator.java | 98 ++++++++++++++----- .../LoanDropdownReadPlatformServiceImpl.java | 3 +- .../loanproduct/service/LoanEnumerations.java | 4 - .../LoanProductReadPlatformServiceImpl.java | 9 +- 26 files changed, 497 insertions(+), 195 deletions(-) create mode 100755 mifosng-db/migrations/core_db/V195__moved_rest_frequency_to_product_level.sql diff --git a/mifosng-db/migrations/core_db/V195__moved_rest_frequency_to_product_level.sql b/mifosng-db/migrations/core_db/V195__moved_rest_frequency_to_product_level.sql new file mode 100755 index 000000000..e840e0eb7 --- /dev/null +++ b/mifosng-db/migrations/core_db/V195__moved_rest_frequency_to_product_level.sql @@ -0,0 +1,9 @@ +ALTER TABLE `m_product_loan_recalculation_details` + ADD COLUMN `rest_frequency_type_enum` SMALLINT(1) NOT NULL AFTER `reschedule_strategy_enum`, + ADD COLUMN `rest_frequency_interval` SMALLINT(3) NOT NULL DEFAULT '0' AFTER `rest_frequency_type_enum`, + ADD COLUMN `rest_freqency_date` DATE NULL DEFAULT NULL AFTER `rest_frequency_interval`; + +ALTER TABLE `m_loan_recalculation_details` + ADD COLUMN `rest_frequency_type_enum` SMALLINT(1) NOT NULL AFTER `reschedule_strategy_enum`, + ADD COLUMN `rest_frequency_interval` SMALLINT(3) NOT NULL DEFAULT '0' AFTER `rest_frequency_type_enum`, + ADD COLUMN `rest_freqency_date` DATE NULL DEFAULT NULL AFTER `rest_frequency_interval`; \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/DataValidatorBuilder.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/DataValidatorBuilder.java index fd41aa592..ff76fb418 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/DataValidatorBuilder.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/DataValidatorBuilder.java @@ -821,5 +821,23 @@ public class DataValidatorBuilder { } return this; } + + public DataValidatorBuilder validateDateBeforeOrEqual(final LocalDate date) { + if (this.value == null && this.ignoreNullValue) { return this; } + + if (this.value != null && date != null) { + final LocalDate dateVal = (LocalDate) this.value; + if (!date.isAfter(dateVal)) { + final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".") + .append(this.parameter).append(".is.greater.than.date"); + final StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(this.parameter) + .append(" must be less than or equal to provided date").append(date); + final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), + defaultEnglishMessage.toString(), this.parameter, dateVal, date); + this.dataValidationErrors.add(error); + } + } + return this; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoanApiConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoanApiConstants.java index 8329a4437..24e998af1 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoanApiConstants.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoanApiConstants.java @@ -33,7 +33,6 @@ public interface LoanApiConstants { public static final String isInterestRecalculationEnabledParameterName = "isInterestRecalculationEnabled"; public static final String daysInYearTypeParameterName = "daysInYearType"; public static final String daysInMonthTypeParameterName = "daysInMonthType"; - public static final String recalculationFrequencyTypeParameterName = "recalculationFrequencyType"; public static final String interestRecalculationCompoundingMethodParameterName = "interestRecalculationCompoundingMethod"; public static final String rescheduleStrategyMethodParameterName = "rescheduleStrategyMethod"; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java index 07302aaec..9f545c247 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java @@ -410,7 +410,6 @@ public class LoansApiResource { Collection loanCollateralOptions = null; Collection calendarOptions = null; Collection accountLinkingOptions = null; - List interestRecalculationFrequencyTypeOptions = null; final boolean template = ApiParameterHelper.template(uriInfo.getQueryParameters()); if (template) { @@ -452,9 +451,6 @@ public class LoansApiResource { calendarOptions = this.loanReadPlatformService.retrieveCalendars(loanBasicDetails.groupId()); } - interestRecalculationFrequencyTypeOptions = this.dropdownReadPlatformService - .retrieveInterestRecalculationFrequencyTypeOptions(); - } Collection overdueCharges = this.chargeReadPlatformService.retrieveLoanProductCharges(loanBasicDetails.loanProductId(), @@ -465,7 +461,7 @@ public class LoansApiResource { repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, loanPurposeOptions, loanCollateralOptions, calendarOptions, notes, accountLinkingOptions, linkedAccount, disbursementData, emiAmountVariations, - overdueCharges, interestRecalculationFrequencyTypeOptions); + overdueCharges); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters(), mandatoryResponseParameters); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanAccountData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanAccountData.java index 02de9b249..fb76aa31c 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanAccountData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanAccountData.java @@ -130,7 +130,6 @@ public class LoanAccountData { private final Collection chargeOptions; private final Collection loanCollateralOptions; private final Collection calendarOptions; - private final List interestRecalculationFrequencyTypeOptions; @Transient private final BigDecimal feeChargesAtDisbursementCharged; @@ -261,7 +260,6 @@ public class LoanAccountData { final EnumOptionData daysInYearType = null; final boolean isInterestRecalculationEnabled = false; final LoanInterestRecalculationData interestRecalculationData = null; - final List interestRecalculationFrequencyTypeOptions = null; return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, @@ -277,7 +275,7 @@ public class LoanAccountData { syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, fixedEmiAmount, maxOutstandingLoanBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, daysInYearType, - isInterestRecalculationEnabled, interestRecalculationData, interestRecalculationFrequencyTypeOptions); + isInterestRecalculationEnabled, interestRecalculationData); } /** @@ -371,7 +369,6 @@ public class LoanAccountData { final EnumOptionData daysInYearType = null; final boolean isInterestRecalculationEnabled = false; final LoanInterestRecalculationData interestRecalculationData = null; - final List interestRecalculationFrequencyTypeOptions = null; return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, @@ -386,8 +383,7 @@ public class LoanAccountData { loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, fixedEmiAmount, maxOutstandingLoanBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, - isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, - interestRecalculationFrequencyTypeOptions); + isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData); } public static LoanAccountData populateClientDefaults(final LoanAccountData acc, final LoanAccountData clientAcc) { @@ -409,8 +405,7 @@ public class LoanAccountData { acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges, - acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData, - acc.interestRecalculationFrequencyTypeOptions); + acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData); } /** @@ -505,7 +500,6 @@ public class LoanAccountData { final EnumOptionData daysInYearType = null; final boolean isInterestRecalculationEnabled = false; final LoanInterestRecalculationData interestRecalculationData = null; - final List interestRecalculationFrequencyTypeOptions = null; return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, @@ -520,7 +514,7 @@ public class LoanAccountData { loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, fixedEmiAmount, maxOutstandingBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, - daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, interestRecalculationFrequencyTypeOptions); + daysInYearType, isInterestRecalculationEnabled, interestRecalculationData); } public static LoanAccountData populateGroupDefaults(final LoanAccountData acc, final LoanAccountData groupAcc) { @@ -541,8 +535,7 @@ public class LoanAccountData { acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges, - acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData, - acc.interestRecalculationFrequencyTypeOptions); + acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData); } public static LoanAccountData loanProductWithTemplateDefaults(final LoanProductData product, @@ -552,7 +545,7 @@ public class LoanAccountData { final Collection interestTypeOptions, final Collection interestCalculationPeriodTypeOptions, final Collection fundOptions, final Collection chargeOptions, final Collection loanPurposeOptions, final Collection loanCollateralOptions, - final Integer loanCycleNumber, final List interestRecalculationFrequencyTypeOptions) { + final Integer loanCycleNumber) { final Long id = null; final String accountNo = null; @@ -667,8 +660,7 @@ public class LoanAccountData { notes, accountLinkingOptions, linkedAccount, disbursementData, product.getMultiDisburseLoan(), fixedEmi, product.getOutstandingLoanBalance(), emiAmountVariations, memberVariations, product, inArrears, product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), isNPA, product.getDaysInMonthType(), - product.getDaysInYearType(), product.isInterestRecalculationEnabled(), product.toLoanInterestRecalculationData(), - interestRecalculationFrequencyTypeOptions); + product.getDaysInYearType(), product.isInterestRecalculationEnabled(), product.toLoanInterestRecalculationData()); } public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) { @@ -721,8 +713,7 @@ public class LoanAccountData { acc.linkedAccount, acc.disbursementDetails, product.getMultiDisburseLoan(), acc.fixedEmiAmount, product.getOutstandingLoanBalance(), acc.emiAmountVariations, acc.memberVariations, product, acc.inArrears, product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), acc.isNPA, product.getDaysInMonthType(), - product.getDaysInYearType(), product.isInterestRecalculationEnabled(), product.toLoanInterestRecalculationData(), - acc.interestRecalculationFrequencyTypeOptions); + product.getDaysInYearType(), product.isInterestRecalculationEnabled(), product.toLoanInterestRecalculationData()); } /* @@ -777,7 +768,6 @@ public class LoanAccountData { final Map memberVariations = null; final LoanProductData product = null; final Collection overdueCharges = null; - final List interestRecalculationFrequencyTypeOptions = null; return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, @@ -792,7 +782,7 @@ public class LoanAccountData { loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, fixedEmiAmont, outstandingLoanBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, - daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, interestRecalculationFrequencyTypeOptions); + daysInYearType, isInterestRecalculationEnabled, interestRecalculationData); } /* @@ -812,8 +802,7 @@ public class LoanAccountData { final Collection loanCollateralOptions, final Collection calendarOptions, final Collection notes, final Collection accountLinkingOptions, final PortfolioAccountData linkedAccount, final Collection disbursementDetails, - final Collection emiAmountVariations, final Collection overdueCharges, - final List interestRecalculationFrequencyTypeOptions) { + final Collection emiAmountVariations, final Collection overdueCharges) { return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.fundId, acc.fundName, @@ -831,7 +820,7 @@ public class LoanAccountData { accountLinkingOptions, linkedAccount, disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance, emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType, - acc.isInterestRecalculationEnabled, acc.interestRecalculationData, interestRecalculationFrequencyTypeOptions); + acc.isInterestRecalculationEnabled, acc.interestRecalculationData); } public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final Collection productOptions, @@ -842,8 +831,7 @@ public class LoanAccountData { acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, allowedLoanOfficers, acc.loanPurposeOptions, acc.loanCollateralOptions, calendarOptions, acc.notes, accountLinkingOptions, - acc.linkedAccount, acc.disbursementDetails, acc.emiAmountVariations, acc.overdueCharges, - acc.interestRecalculationFrequencyTypeOptions); + acc.linkedAccount, acc.disbursementDetails, acc.emiAmountVariations, acc.overdueCharges); } public static LoanAccountData associateGroup(final LoanAccountData acc, final GroupGeneralData group) { @@ -863,8 +851,7 @@ public class LoanAccountData { acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges, - acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData, - acc.interestRecalculationFrequencyTypeOptions); + acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData); } public static LoanAccountData associateMemberVariations(final LoanAccountData acc, final Map memberLoanCycle) { @@ -921,8 +908,7 @@ public class LoanAccountData { acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance, acc.emiAmountVariations, memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges, - acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData, - acc.interestRecalculationFrequencyTypeOptions); + acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData); } public static LoanAccountData withInterestRecalculationCalendarData(final LoanAccountData acc, final CalendarData calendarData) { @@ -945,8 +931,7 @@ public class LoanAccountData { acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges, - acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, interestRecalculationData, - acc.interestRecalculationFrequencyTypeOptions); + acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, interestRecalculationData); } private LoanAccountData( @@ -1002,8 +987,7 @@ public class LoanAccountData { final LoanProductData product, final Boolean inArrears, final Integer graceOnArrearsAgeing, final Collection overdueCharges, final Boolean isNPA, final EnumOptionData daysInMonthType, final EnumOptionData daysInYearType, final boolean isInterestRecalculationEnabled, - final LoanInterestRecalculationData interestRecalculationData, - final List interestRecalculationFrequencyTypeOptions) { + final LoanInterestRecalculationData interestRecalculationData) { this.id = id; this.accountNo = accountNo; this.status = status; @@ -1147,13 +1131,6 @@ public class LoanAccountData { this.daysInYearType = daysInYearType; this.isInterestRecalculationEnabled = isInterestRecalculationEnabled; this.interestRecalculationData = interestRecalculationData; - - if (CollectionUtils.isEmpty(interestRecalculationFrequencyTypeOptions)) { - this.interestRecalculationFrequencyTypeOptions = null; - } else { - this.interestRecalculationFrequencyTypeOptions = interestRecalculationFrequencyTypeOptions; - } - } public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanInterestRecalculationData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanInterestRecalculationData.java index 8c70f4cdd..46bd704e5 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanInterestRecalculationData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanInterestRecalculationData.java @@ -5,6 +5,7 @@ */ package org.mifosplatform.portfolio.loanaccount.data; +import org.joda.time.LocalDate; import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.portfolio.calendar.data.CalendarData; @@ -16,20 +17,30 @@ public class LoanInterestRecalculationData { private final EnumOptionData rescheduleStrategyType; @SuppressWarnings("unused") private final CalendarData calendarData; + private final EnumOptionData recalculationRestFrequencyType; + private final Integer recalculationRestFrequencyInterval; + private final LocalDate recalculationRestFrequencyDate; public LoanInterestRecalculationData(final Long id, final Long loanId, final EnumOptionData interestRecalculationCompoundingType, - final EnumOptionData rescheduleStrategyType, final CalendarData calendarData) { + final EnumOptionData rescheduleStrategyType, final CalendarData calendarData, + final EnumOptionData recalculationRestFrequencyType, final Integer recalculationRestFrequencyInterval, + final LocalDate recalculationRestFrequencyDate) { this.id = id; this.loanId = loanId; this.interestRecalculationCompoundingType = interestRecalculationCompoundingType; this.rescheduleStrategyType = rescheduleStrategyType; this.calendarData = calendarData; + this.recalculationRestFrequencyType = recalculationRestFrequencyType; + this.recalculationRestFrequencyInterval = recalculationRestFrequencyInterval; + this.recalculationRestFrequencyDate = recalculationRestFrequencyDate; } public static LoanInterestRecalculationData withCalendarData(final LoanInterestRecalculationData recalculationData, final CalendarData calendarData) { return new LoanInterestRecalculationData(recalculationData.id, recalculationData.loanId, - recalculationData.interestRecalculationCompoundingType, recalculationData.rescheduleStrategyType, calendarData); + recalculationData.interestRecalculationCompoundingType, recalculationData.rescheduleStrategyType, calendarData, + recalculationData.recalculationRestFrequencyType, recalculationData.recalculationRestFrequencyInterval, + recalculationData.recalculationRestFrequencyDate); } public Long getId() { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java index d9fdaa4ee..5cc4d8fe4 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java @@ -90,10 +90,12 @@ import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleG import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory; import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel; import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod; +import org.mifosplatform.portfolio.loanproduct.LoanProductConstants; import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod; import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct; import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail; import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy; +import org.mifosplatform.portfolio.loanproduct.domain.RecalculationFrequencyType; import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations; import org.mifosplatform.useradministration.domain.AppUser; import org.springframework.data.jpa.domain.AbstractPersistable; @@ -1057,6 +1059,9 @@ public class Loan extends AbstractPersistable { final String dateFormatAsInput = command.dateFormat(); final String localeAsInput = command.locale(); + final LocalDate recalculationRestFrequencyDate = command + .localDateValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName); + updateLoanInterestRecalculationSettings(recalculationRestFrequencyDate, command, actualChanges); final String accountNoParamName = "accountNo"; if (command.isChangeInStringParameterNamed(accountNoParamName, this.accountNumber)) { @@ -1299,15 +1304,24 @@ public class Loan extends AbstractPersistable { /** * Update interest recalculation settings if product configuration changes */ - public void updateLoanInterestRecalculationSettings() { + public void updateLoanInterestRecalculationSettings(final LocalDate recalculationRestFrequencyDate, final JsonCommand command, + final Map actualChanges) { if (isInterestRecalculationEnabledForProduct()) { + Date restFrequencyDate = null; + if (recalculationRestFrequencyDate != null) { + restFrequencyDate = recalculationRestFrequencyDate.toDate(); + } if (this.loanInterestRecalculationDetails == null) { - this.loanInterestRecalculationDetails = this.loanProduct.copyInterestRecalculationSettings(); + this.loanInterestRecalculationDetails = LoanInterestRecalculationDetails.createFrom(this.loanProduct + .getProductInterestRecalculationDetails().getInterestRecalculationCompoundingMethod(), this.loanProduct + .getProductInterestRecalculationDetails().getRescheduleStrategyMethod(), this.loanProduct + .getProductInterestRecalculationDetails().getRestFrequencyType().getValue(), this.loanProduct + .getProductInterestRecalculationDetails().getRestInterval(), restFrequencyDate); this.loanInterestRecalculationDetails.updateLoan(this); } else { - this.loanInterestRecalculationDetails = this.loanProduct - .updateLoanInterestRecalculationDetails(this.loanInterestRecalculationDetails); + + this.loanInterestRecalculationDetails.update(command, actualChanges); } } else { this.loanInterestRecalculationDetails = null; @@ -1479,7 +1493,7 @@ public class Loan extends AbstractPersistable { public void loanApplicationSubmittal(final AppUser currentUser, final LoanScheduleModel loanSchedule, final LoanApplicationTerms loanApplicationTerms, final LoanLifecycleStateMachine lifecycleStateMachine, final LocalDate submittedOn, final String externalId, final boolean allowTransactionsOnHoliday, final List holidays, - final WorkingDays workingDays, final boolean allowTransactionsOnNonWorkingDay) { + final WorkingDays workingDays, final boolean allowTransactionsOnNonWorkingDay, final LocalDate recalculationRestFrequencyDate) { updateLoanSchedule(loanSchedule); @@ -1542,7 +1556,15 @@ public class Loan extends AbstractPersistable { * enabled */ if (this.loanRepaymentScheduleDetail.isInterestRecalculationEnabled()) { - this.loanInterestRecalculationDetails = this.loanProduct.copyInterestRecalculationSettings(); + Date restFrequencyDate = null; + if (recalculationRestFrequencyDate != null) { + restFrequencyDate = recalculationRestFrequencyDate.toDate(); + } + this.loanInterestRecalculationDetails = LoanInterestRecalculationDetails.createFrom(this.loanProduct + .getProductInterestRecalculationDetails().getInterestRecalculationCompoundingMethod(), this.loanProduct + .getProductInterestRecalculationDetails().getRescheduleStrategyMethod(), this.loanProduct + .getProductInterestRecalculationDetails().getRestFrequencyType().getValue(), this.loanProduct + .getProductInterestRecalculationDetails().getRestInterval(), restFrequencyDate); this.loanInterestRecalculationDetails.updateLoan(this); } @@ -4106,12 +4128,14 @@ public class Loan extends AbstractPersistable { loanVariationTermsData.add(data); } + RecalculationFrequencyType recalculationFrequencyType = this.loanInterestRecalculationDetails().getRestFrequencyType(); + final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(), calculatedRepaymentsStartingFromDate, getInArrearsTolerance(), this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData, this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate(), this.loanInterestRecalculationDetails, - calendarInstanceForInterestRecalculation); + calendarInstanceForInterestRecalculation, recalculationFrequencyType); final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory .determineProcessor(this.transactionProcessingStrategy); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanInterestRecalculationDetails.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanInterestRecalculationDetails.java index ddd058a42..f84cb4fbd 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanInterestRecalculationDetails.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanInterestRecalculationDetails.java @@ -5,14 +5,23 @@ */ package org.mifosplatform.portfolio.loanaccount.domain; +import java.util.Date; +import java.util.Map; + import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.OneToOne; import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.portfolio.loanproduct.LoanProductConstants; import org.mifosplatform.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod; import org.mifosplatform.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod; +import org.mifosplatform.portfolio.loanproduct.domain.RecalculationFrequencyType; import org.springframework.data.jpa.domain.AbstractPersistable; /** @@ -43,27 +52,53 @@ public class LoanInterestRecalculationDetails extends AbstractPersistable @Column(name = "reschedule_strategy_enum", nullable = false) private Integer rescheduleStrategyMethod; + @Column(name = "rest_frequency_type_enum", nullable = false) + private Integer restFrequencyType; + + @Column(name = "rest_frequency_interval", nullable = false) + private Integer restInterval; + + @Temporal(TemporalType.DATE) + @Column(name = "rest_freqency_date") + private Date restFrequencyDate; + protected LoanInterestRecalculationDetails() { // Default constructor for jpa repository } - private LoanInterestRecalculationDetails(final Integer interestRecalculationCompoundingMethod, final Integer rescheduleStrategyMethod) { + private LoanInterestRecalculationDetails(final Integer interestRecalculationCompoundingMethod, final Integer rescheduleStrategyMethod, + final Integer restFrequencyType, final Integer restInterval, final Date restFrequencyDate) { this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod; this.rescheduleStrategyMethod = rescheduleStrategyMethod; + this.restFrequencyDate = restFrequencyDate; + this.restFrequencyType = restFrequencyType; + this.restInterval = restInterval; } public static LoanInterestRecalculationDetails createFrom(final Integer interestRecalculationCompoundingMethod, - final Integer rescheduleStrategyMethod) { - return new LoanInterestRecalculationDetails(interestRecalculationCompoundingMethod, rescheduleStrategyMethod); + final Integer rescheduleStrategyMethod, final Integer restFrequencyType, final Integer restInterval, + final Date restFrequencyDate) { + return new LoanInterestRecalculationDetails(interestRecalculationCompoundingMethod, rescheduleStrategyMethod, restFrequencyType, + restInterval, restFrequencyDate); } public void updateLoan(final Loan loan) { this.loan = loan; } - public void update(final Integer interestRecalculationCompoundingMethod, final Integer rescheduleStrategyMethod) { - this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod; - this.rescheduleStrategyMethod = rescheduleStrategyMethod; + public void update(final JsonCommand command, final Map actualChanges) { + if (command.isChangeInLocalDateParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName, + getRestFrequencyLocalDate())) { + final String dateFormatAsInput = command.dateFormat(); + final String localeAsInput = command.locale(); + final String valueAsInput = command.stringValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName); + actualChanges.put(LoanProductConstants.recalculationRestFrequencyDateParamName, valueAsInput); + actualChanges.put("dateFormat", dateFormatAsInput); + actualChanges.put("locale", localeAsInput); + + final LocalDate newValue = command.localDateValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName); + this.restFrequencyDate = newValue.toDate(); + } } public InterestRecalculationCompoundingMethod getInterestRecalculationCompoundingMethod() { @@ -74,4 +109,20 @@ public class LoanInterestRecalculationDetails extends AbstractPersistable return LoanRescheduleStrategyMethod.fromInt(this.rescheduleStrategyMethod); } + public LocalDate getRestFrequencyLocalDate() { + LocalDate recurrenceOnLocalDate = null; + if (this.restFrequencyDate != null) { + recurrenceOnLocalDate = new LocalDate(this.restFrequencyDate); + } + return recurrenceOnLocalDate; + } + + public RecalculationFrequencyType getRestFrequencyType() { + return RecalculationFrequencyType.fromInt(this.restFrequencyType); + } + + + public Integer getRestInterval() { + return this.restInterval; + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java index 2bb3dc82b..f564e8a0e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java @@ -1022,16 +1022,15 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener recalculationDates, preCloseTransaction); } - @SuppressWarnings("unused") private LocalDate getNextRestScheduleDate(LocalDate startDate, LoanApplicationTerms loanApplicationTerms, final boolean isHolidayEnabled, final List holidays, final WorkingDays workingDays) { CalendarInstance calendarInstance = loanApplicationTerms.getRestCalendarInstance(); LocalDate nextScheduleDate = CalendarUtils.getNextScheduleDate(calendarInstance.getCalendar(), startDate); - /* - * nextScheduleDate = - * this.scheduledDateGenerator.adjustRepaymentDate(nextScheduleDate, - * loanApplicationTerms, isHolidayEnabled, holidays, workingDays); - */ + if (loanApplicationTerms.getRecalculationFrequencyType().isSameAsRepayment()) { + nextScheduleDate = this.scheduledDateGenerator.adjustRepaymentDate(nextScheduleDate, loanApplicationTerms, isHolidayEnabled, + holidays, workingDays); + } + return nextScheduleDate; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java index cb2cb8d06..8aa9c6c00 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java @@ -31,6 +31,7 @@ import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod; import org.mifosplatform.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod; import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail; import org.mifosplatform.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod; +import org.mifosplatform.portfolio.loanproduct.domain.RecalculationFrequencyType; public final class LoanApplicationTerms { @@ -122,6 +123,8 @@ public final class LoanApplicationTerms { private final CalendarInstance restCalendarInstance; + private final RecalculationFrequencyType recalculationFrequencyType; + public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency, final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType, final AmortizationMethod amortizationMethod, @@ -139,13 +142,15 @@ public final class LoanApplicationTerms { final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null; final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null; final CalendarInstance restCalendarInstance = null; + final RecalculationFrequencyType recalculationFrequencyType = null; return new LoanApplicationTerms(currency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentPeriodFrequencyType, amortizationMethod, interestMethod, interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, principalMoney, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, emiAmountVariations, graceOnArrearsAgeing, daysInMonthType, daysInYearType, - isInterestRecalculationEnabled, rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance); + isInterestRecalculationEnabled, rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance, + recalculationFrequencyType); } public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency, @@ -179,6 +184,7 @@ public final class LoanApplicationTerms { final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null; final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null; final CalendarInstance restCalendarInstance = null; + final RecalculationFrequencyType recalculationFrequencyType = null; return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentPeriodFrequencyType, amortizationMethod, interestMethod, interestRatePerPeriod, @@ -187,7 +193,7 @@ public final class LoanApplicationTerms { graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, emiAmountVariations, loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod, - interestRecalculationCompoundingMethod, restCalendarInstance); + interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType); } public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency, @@ -196,7 +202,8 @@ public final class LoanApplicationTerms { final Money inArrearsTolerance, final LoanProductRelatedDetail loanProductRelatedDetail, final boolean multiDisburseLoan, final BigDecimal emiAmount, final List disbursementDatas, final BigDecimal maxOutstandingBalance, final List emiAmountVariations, final LocalDate interestChargedFromDate, - final LoanInterestRecalculationDetails interestRecalculationDetails, final CalendarInstance restCalendarInstance) { + final LoanInterestRecalculationDetails interestRecalculationDetails, final CalendarInstance restCalendarInstance, + final RecalculationFrequencyType recalculationFrequencyType) { final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments(); final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery(); @@ -233,7 +240,7 @@ public final class LoanApplicationTerms { graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, emiAmountVariations, loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod, - interestRecalculationCompoundingMethod, restCalendarInstance); + interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType); } public static LoanApplicationTerms assembleFrom(final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType, @@ -250,7 +257,8 @@ public final class LoanApplicationTerms { applicationTerms.disbursementDatas, applicationTerms.maxOutstandingBalance, applicationTerms.emiAmountVariations, applicationTerms.graceOnArrearsAgeing, applicationTerms.daysInMonthType, applicationTerms.daysInYearType, applicationTerms.interestRecalculationEnabled, applicationTerms.rescheduleStrategyMethod, - applicationTerms.interestRecalculationCompoundingMethod, applicationTerms.restCalendarInstance); + applicationTerms.interestRecalculationCompoundingMethod, applicationTerms.restCalendarInstance, + applicationTerms.recalculationFrequencyType); } private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency, @@ -266,7 +274,8 @@ public final class LoanApplicationTerms { final BigDecimal maxOutstandingBalance, final List emiAmountVariations, final Integer graceOnArrearsAgeing, final DaysInMonthType daysInMonthType, final DaysInYearType daysInYearType, final boolean isInterestRecalculationEnabled, final LoanRescheduleStrategyMethod rescheduleStrategyMethod, - final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod, final CalendarInstance restCalendarInstance) { + final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod, + final CalendarInstance restCalendarInstance, final RecalculationFrequencyType recalculationFrequencyType) { this.currency = currency; this.loanTermFrequency = loanTermFrequency; this.loanTermPeriodFrequencyType = loanTermPeriodFrequencyType; @@ -304,6 +313,7 @@ public final class LoanApplicationTerms { this.rescheduleStrategyMethod = rescheduleStrategyMethod; this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod; this.restCalendarInstance = restCalendarInstance; + this.recalculationFrequencyType = recalculationFrequencyType; } public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate, @@ -1052,4 +1062,9 @@ public final class LoanApplicationTerms { } return numberOfPeriods; } + + + public RecalculationFrequencyType getRecalculationFrequencyType() { + return this.recalculationFrequencyType; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java index f9b270dff..b465b4b6c 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java @@ -41,7 +41,7 @@ public final class CalculateLoanScheduleQueryFromApiJsonHelper { "graceOnInterestCharged", "interestChargedFromDate", "submittedOnDate", "submittedOnNote", "locale", "dateFormat", "charges", "collateral", "syncDisbursementWithMeeting", "linkAccountId", LoanApiConstants.disbursementDataParameterName, LoanApiConstants.emiAmountParameterName, LoanApiConstants.maxOutstandingBalanceParameterName, - LoanProductConstants.graceOnArrearsAgeingParameterName, LoanApiConstants.recalculationFrequencyTypeParameterName)); + LoanProductConstants.graceOnArrearsAgeingParameterName, LoanProductConstants.recalculationRestFrequencyDateParamName)); private final FromJsonHelper fromApiJsonHelper; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java index 9acbd6a7a..ee2d9c7af 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java @@ -5,8 +5,6 @@ */ package org.mifosplatform.portfolio.loanaccount.serialization; -import static org.mifosplatform.portfolio.loanaccount.api.LoanApiConstants.recalculationFrequencyTypeParameterName; - import java.lang.reflect.Type; import java.math.BigDecimal; import java.util.ArrayList; @@ -48,21 +46,26 @@ public final class LoanApplicationCommandFromApiJsonHelper { final Set supportedParameters = new HashSet<>(Arrays.asList("dateFormat", "locale", "id", "clientId", "groupId", "loanType", "productId", "principal", "loanTermFrequency", "loanTermFrequencyType", "numberOfRepayments", "repaymentEvery", "repaymentFrequencyType", "interestRatePerPeriod", "amortizationType", "interestType", "interestCalculationPeriodType", - "expectedDisbursementDate", "repaymentsStartingFromDate", "graceOnPrincipalPayment", "graceOnInterestPayment", + "expectedDisbursementDate", "repaymentsStartingFromDate", "graceOnPrincipalPayment", + "graceOnInterestPayment", "graceOnInterestCharged", "interestChargedFromDate", // "submittedOnDate", "submittedOnNote", // - "accountNo", "externalId", "fundId", + "accountNo", + "externalId", + "fundId", "loanOfficerId", // optional - "loanPurposeId", "inArrearsTolerance", "charges", + "loanPurposeId", + "inArrearsTolerance", + "charges", "collateral", // optional "transactionProcessingStrategyId", // settings "calendarId", // optional "syncDisbursementWithMeeting",// optional "linkAccountId", LoanApiConstants.disbursementDataParameterName, LoanApiConstants.emiAmountParameterName, LoanApiConstants.maxOutstandingBalanceParameterName, LoanProductConstants.graceOnArrearsAgeingParameterName, - LoanApiConstants.recalculationFrequencyTypeParameterName)); + LoanProductConstants.recalculationRestFrequencyDateParamName)); private final FromJsonHelper fromApiJsonHelper; private final CalculateLoanScheduleQueryFromApiJsonHelper apiJsonHelper; @@ -360,13 +363,6 @@ public final class LoanApplicationCommandFromApiJsonHelper { } validateLoanMultiDisbursementdate(element, baseDataValidator, expectedDisbursementDate, principal); - if (this.fromApiJsonHelper.parameterExists(LoanApiConstants.recalculationFrequencyTypeParameterName, element)) { - final Integer recalculationFrequencyType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed( - LoanApiConstants.recalculationFrequencyTypeParameterName, element); - baseDataValidator.reset().parameter(LoanApiConstants.recalculationFrequencyTypeParameterName).value(recalculationFrequencyType) - .notNull().inMinMaxRange(1, 5); - } - if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } } @@ -452,7 +448,8 @@ public final class LoanApplicationCommandFromApiJsonHelper { atLeastOneParameterPassedForUpdate = true; final BigDecimal inArrearsTolerance = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(inArrearsToleranceParameterName, element); - baseDataValidator.reset().parameter(inArrearsToleranceParameterName).value(inArrearsTolerance).ignoreIfNull().zeroOrPositiveAmount(); + baseDataValidator.reset().parameter(inArrearsToleranceParameterName).value(inArrearsTolerance).ignoreIfNull() + .zeroOrPositiveAmount(); } final String loanTermFrequencyParameterName = "loanTermFrequency"; @@ -839,11 +836,11 @@ public final class LoanApplicationCommandFromApiJsonHelper { } - public void validateRecalcuationFrequencyType(final Integer recalculationFrequencyTypeValue) { + public void validateRecalcuationFrequency(final LocalDate recalculationFrequencyDate, final LocalDate expectedDisbursementDate) { final List dataValidationErrors = new ArrayList<>(); final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan"); - baseDataValidator.reset().parameter(recalculationFrequencyTypeParameterName).value(recalculationFrequencyTypeValue).notNull() - .inMinMaxRange(1, 5); + baseDataValidator.reset().parameter(LoanProductConstants.recalculationRestFrequencyDateParamName).value(recalculationFrequencyDate) + .notNull().validateDateBeforeOrEqual(expectedDisbursementDate); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java index d8154291d..28be6003f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java @@ -5,8 +5,6 @@ */ package org.mifosplatform.portfolio.loanaccount.service; -import static org.mifosplatform.portfolio.loanaccount.api.LoanApiConstants.recalculationFrequencyTypeParameterName; - import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -70,6 +68,7 @@ import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleM import org.mifosplatform.portfolio.loanaccount.loanschedule.service.LoanScheduleCalculationPlatformService; import org.mifosplatform.portfolio.loanaccount.serialization.LoanApplicationCommandFromApiJsonHelper; import org.mifosplatform.portfolio.loanaccount.serialization.LoanApplicationTransitionApiJsonValidator; +import org.mifosplatform.portfolio.loanproduct.LoanProductConstants; import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct; import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail; import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository; @@ -214,11 +213,13 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa if (loanProduct.isInterestRecalculationEnabled()) { - final Integer recalculationFrequencyTypeValue = command - .integerValueOfParameterNamed(recalculationFrequencyTypeParameterName); - this.fromApiJsonDeserializer.validateRecalcuationFrequencyType(recalculationFrequencyTypeValue); - - createAndPersistCalendarInstanceForInterestRecalculation(newLoanApplication, recalculationFrequencyTypeValue); + final LocalDate recalculationFrequencyDate = this.fromJsonHelper.extractLocalDateNamed( + LoanProductConstants.recalculationRestFrequencyDateParamName, command.parsedJson()); + if (!newLoanApplication.loanInterestRecalculationDetails().getRestFrequencyType().isSameAsRepayment()) { + this.fromApiJsonDeserializer.validateRecalcuationFrequency(recalculationFrequencyDate, + newLoanApplication.getExpectedDisbursedOnLocalDate()); + } + createAndPersistCalendarInstanceForInterestRecalculation(newLoanApplication); } if (newLoanApplication.isAccountNumberRequiresAutoGeneration()) { @@ -271,33 +272,30 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa } } - private void createAndPersistCalendarInstanceForInterestRecalculation(final Loan loan, final Integer recalculationFrequencyTypeValue) { + private void createAndPersistCalendarInstanceForInterestRecalculation(final Loan loan) { - final LocalDate calendarStartDate = loan.getDisbursementDate(); + LocalDate calendarStartDate = loan.loanInterestRecalculationDetails().getRestFrequencyLocalDate(); + if (calendarStartDate == null) { + calendarStartDate = loan.getExpectedDisbursedOnLocalDate(); + } final Integer repeatsOnDay = calendarStartDate.getDayOfWeek(); - final RecalculationFrequencyType recalculationFrequencyType = RecalculationFrequencyType.fromInt(recalculationFrequencyTypeValue); + final RecalculationFrequencyType recalculationFrequencyType = loan.loanInterestRecalculationDetails().getRestFrequencyType(); - Integer frequency = 1; + Integer frequency = loan.loanInterestRecalculationDetails().getRestInterval(); CalendarFrequencyType calendarFrequencyType = CalendarFrequencyType.INVALID; switch (recalculationFrequencyType) { case DAILY: - frequency = 1; calendarFrequencyType = CalendarFrequencyType.DAILY; break; - case FORTNIGHTLY: - frequency = 2; - calendarFrequencyType = CalendarFrequencyType.WEEKLY; - break; case MONTHLY: - frequency = 1; calendarFrequencyType = CalendarFrequencyType.MONTHLY; break; case SAME_AS_REPAYMENT_PERIOD: frequency = loan.repaymentScheduleDetail().getRepayEvery(); calendarFrequencyType = CalendarFrequencyType.from(loan.repaymentScheduleDetail().getRepaymentPeriodFrequencyType()); + calendarStartDate = loan.getExpectedDisbursedOnLocalDate(); break; case WEEKLY: - frequency = 1; calendarFrequencyType = CalendarFrequencyType.WEEKLY; break; default: @@ -313,35 +311,32 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa } - private void updateCalendarDetailsForInterestRecalculation(final CalendarInstance calendarInstance, final Loan loan, - final Integer recalculationFrequencyTypeValue) { + private void updateCalendarDetailsForInterestRecalculation(final CalendarInstance calendarInstance, final Loan loan) { Calendar interestRecalculationRecurrings = calendarInstance.getCalendar(); - final LocalDate calendarStartDate = loan.getDisbursementDate(); + LocalDate calendarStartDate = loan.loanInterestRecalculationDetails().getRestFrequencyLocalDate(); + if (calendarStartDate == null) { + calendarStartDate = loan.getExpectedDisbursedOnLocalDate(); + } final Integer repeatsOnDay = calendarStartDate.getDayOfWeek(); - final RecalculationFrequencyType recalculationFrequencyType = RecalculationFrequencyType.fromInt(recalculationFrequencyTypeValue); + final RecalculationFrequencyType recalculationFrequencyType = loan.loanInterestRecalculationDetails().getRestFrequencyType(); - Integer frequency = 1; + Integer frequency = loan.loanInterestRecalculationDetails().getRestInterval(); CalendarFrequencyType calendarFrequencyType = CalendarFrequencyType.INVALID; switch (recalculationFrequencyType) { case DAILY: - frequency = 1; calendarFrequencyType = CalendarFrequencyType.DAILY; break; - case FORTNIGHTLY: - frequency = 2; - calendarFrequencyType = CalendarFrequencyType.WEEKLY; - break; + case MONTHLY: - frequency = 1; calendarFrequencyType = CalendarFrequencyType.MONTHLY; break; case SAME_AS_REPAYMENT_PERIOD: + calendarStartDate = loan.getExpectedDisbursedOnLocalDate(); frequency = loan.repaymentScheduleDetail().getRepayEvery(); calendarFrequencyType = CalendarFrequencyType.from(loan.repaymentScheduleDetail().getRepaymentPeriodFrequencyType()); break; case WEEKLY: - frequency = 1; calendarFrequencyType = CalendarFrequencyType.WEEKLY; break; default: @@ -616,26 +611,29 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa // updating loan interest recalculation details throwing null // pointer exception after saveAndFlush // http://stackoverflow.com/questions/17151757/hibernate-cascade-update-gives-null-pointer/17334374#17334374 - existingLoanApplication.updateLoanInterestRecalculationSettings(); this.loanRepository.save(existingLoanApplication); if (productRelatedDetail.isInterestRecalculationEnabled()) { - - final Integer recalculationFrequencyTypeValue = command - .integerValueOfParameterNamed(recalculationFrequencyTypeParameterName); - - this.fromApiJsonDeserializer.validateRecalcuationFrequencyType(recalculationFrequencyTypeValue); + LocalDate recalculationFrequencyDate = existingLoanApplication.loanProduct().getProductInterestRecalculationDetails() + .getRestFrequencyLocalDate(); + if (this.fromJsonHelper.parameterExists(LoanProductConstants.recalculationRestFrequencyDateParamName, command.parsedJson())) { + recalculationFrequencyDate = this.fromJsonHelper.extractLocalDateNamed( + LoanProductConstants.recalculationRestFrequencyDateParamName, command.parsedJson()); + if (!existingLoanApplication.loanInterestRecalculationDetails().getRestFrequencyType().isSameAsRepayment()) { + this.fromApiJsonDeserializer.validateRecalcuationFrequency(recalculationFrequencyDate, + existingLoanApplication.getExpectedDisbursedOnLocalDate()); + } + } CalendarInstance calendarInstance = this.calendarInstanceRepository.findByEntityIdAndEntityTypeIdAndCalendarTypeId( existingLoanApplication.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue(), CalendarType.COLLECTION.getValue()); if (calendarInstance == null) { - createAndPersistCalendarInstanceForInterestRecalculation(existingLoanApplication, recalculationFrequencyTypeValue); + createAndPersistCalendarInstanceForInterestRecalculation(existingLoanApplication); } else { - updateCalendarDetailsForInterestRecalculation(calendarInstance, existingLoanApplication, - recalculationFrequencyTypeValue); + updateCalendarDetailsForInterestRecalculation(calendarInstance, existingLoanApplication); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAssembler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAssembler.java index baa6da740..1d89bbdd2 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAssembler.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAssembler.java @@ -61,6 +61,7 @@ import org.mifosplatform.portfolio.loanaccount.exception.MultiDisbursementDataRe import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms; import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel; import org.mifosplatform.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler; +import org.mifosplatform.portfolio.loanproduct.LoanProductConstants; import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct; import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail; import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository; @@ -260,6 +261,8 @@ public class LoanAssembler { loanDisbursementDetails.updateLoan(loanApplication); } } + + final LocalDate recalculationRestFrequencyDate = this.fromApiJsonHelper.extractLocalDateNamed(LoanProductConstants.recalculationRestFrequencyDateParamName, element); final LoanApplicationTerms loanApplicationTerms = this.loanScheduleAssembler.assembleLoanTerms(element); final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled(); @@ -271,7 +274,8 @@ public class LoanAssembler { final LoanScheduleModel loanScheduleModel = this.loanScheduleAssembler.assembleLoanScheduleFrom(loanApplicationTerms, isHolidayEnabled, holidays, workingDays, element); loanApplication.loanApplicationSubmittal(currentUser, loanScheduleModel, loanApplicationTerms, defaultLoanLifecycleStateMachine(), - submittedOnDate, externalId, allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay); + submittedOnDate, externalId, allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay, + recalculationRestFrequencyDate); return loanApplication; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java index 6256bb6ed..991e828ed 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java @@ -533,7 +533,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { + " l.loan_counter as loanCounter, l.loan_product_counter as loanProductCounter," + " l.is_npa as isNPA, l.days_in_month_enum as daysInMonth, l.days_in_year_enum as daysInYear, " + " l.interest_recalculation_enabled as isInterestRecalculationEnabled, " - + " lir.id as lirId, lir.loan_id as loanId, lir.compound_type_enum as compoundType, lir.reschedule_strategy_enum as rescheduleStrategy " + + " lir.id as lirId, lir.loan_id as loanId, lir.compound_type_enum as compoundType, lir.reschedule_strategy_enum as rescheduleStrategy, " + + " lir.rest_frequency_type_enum as restFrequencyEnum, lir.rest_frequency_interval as restFrequencyInterval, " + + " lir.rest_freqency_date as restFrequencyDate " + " 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 " @@ -775,9 +777,13 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final int rescheduleStrategyEnumValue = JdbcSupport.getInteger(rs, "rescheduleStrategy"); final EnumOptionData rescheduleStrategyType = LoanEnumerations.rescheduleStrategyType(rescheduleStrategyEnumValue); final CalendarData calendarData = null; + final int restFrequencyEnumValue = JdbcSupport.getInteger(rs, "restFrequencyEnum"); + final EnumOptionData restFrequencyType = LoanEnumerations.interestRecalculationFrequencyType(restFrequencyEnumValue); + final int restFrequencyInterval = JdbcSupport.getInteger(rs, "restFrequencyInterval"); + final LocalDate restFrequencyDate = JdbcSupport.getLocalDate(rs, "restFrequencyDate"); interestRecalculationData = new LoanInterestRecalculationData(lprId, productId, interestRecalculationCompoundingType, - rescheduleStrategyType, calendarData); + rescheduleStrategyType, calendarData, restFrequencyType, restFrequencyInterval, restFrequencyDate); } return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, groupData, @@ -1220,13 +1226,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { } } - final List interestRecalculationFrequencyTypeOptions = this.loanDropdownReadPlatformService - .retrieveInterestRecalculationFrequencyTypeOptions(); - return LoanAccountData.loanProductWithTemplateDefaults(loanProduct, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, loanPurposeOptions, loanCollateralOptions, - loanCycleCounter, interestRecalculationFrequencyTypeOptions); + loanCycleCounter); } @Override diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/LoanProductConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/LoanProductConstants.java index 2fa38570c..bfe23d0a7 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/LoanProductConstants.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/LoanProductConstants.java @@ -68,5 +68,8 @@ public interface LoanProductConstants { public static final String daysInMonthTypeParameterName = "daysInMonthType"; public static final String interestRecalculationCompoundingMethodParameterName = "interestRecalculationCompoundingMethod"; public static final String rescheduleStrategyMethodParameterName = "rescheduleStrategyMethod"; + public static final String recalculationRestFrequencyTypeParameterName = "recalculationRestFrequencyType"; + public static final String recalculationRestFrequencyIntervalParameterName = "recalculationRestFrequencyInterval"; + public static final String recalculationRestFrequencyDateParamName = "recalculationRestFrequencyDate"; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java index 1726559ac..73991652c 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java @@ -76,8 +76,8 @@ public class LoanProductsApiResource { "transactionProcessingStrategyOptions", "chargeOptions", "accountingOptions", "accountingRuleOptions", "accountingMappingOptions")); - private final Set PRODUCT_MIX_DATA_PARAMETERS = new HashSet<>(Arrays.asList("productId", "productName", - "restrictedProducts", "allowedProducts", "productOptions")); + private final Set PRODUCT_MIX_DATA_PARAMETERS = new HashSet<>(Arrays.asList("productId", "productName", "restrictedProducts", + "allowedProducts", "productOptions")); private final String resourceNameForPermissions = "LOANPRODUCT"; @@ -277,12 +277,14 @@ public class LoanProductsApiResource { final List interestRecalculationCompoundingTypeOptions = dropdownReadPlatformService .retrieveInterestRecalculationCompoundingTypeOptions(); final List rescheduleStrategyTypeOptions = dropdownReadPlatformService.retrieveRescheduleStrategyTypeOptions(); + final List interestRecalculationFrequencyTypeOptions = dropdownReadPlatformService + .retrieveInterestRecalculationFrequencyTypeOptions(); return new LoanProductData(productData, chargeOptions, penaltyOptions, paymentTypeOptions, currencyOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, repaymentFrequencyTypeOptions, interestRateFrequencyTypeOptions, fundOptions, transactionProcessingStrategyOptions, accountOptions, accountingRuleTypeOptions, loanCycleValueConditionTypeOptions, daysInMonthTypeOptions, daysInYearTypeOptions, - interestRecalculationCompoundingTypeOptions, rescheduleStrategyTypeOptions); + interestRecalculationCompoundingTypeOptions, rescheduleStrategyTypeOptions, interestRecalculationFrequencyTypeOptions); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java index c50f696c6..017f8e330 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java @@ -32,6 +32,7 @@ import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod; import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod; import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod; import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations; +import org.springframework.util.CollectionUtils; /** * Immutable data object to represent loan products. @@ -126,6 +127,8 @@ public class LoanProductData { @SuppressWarnings("unused") private final List rescheduleStrategyTypeOptions; + private final List interestRecalculationFrequencyTypeOptions; + private final Boolean multiDisburseLoan; private final Integer maxTrancheCount; private final BigDecimal outstandingLoanBalance; @@ -427,6 +430,7 @@ public class LoanProductData { this.daysInYearTypeOptions = null; this.interestRecalculationCompoundingTypeOptions = null; this.rescheduleStrategyTypeOptions = null; + this.interestRecalculationFrequencyTypeOptions = null; } public LoanProductData(final LoanProductData productData, final Collection chargeOptions, @@ -438,7 +442,7 @@ public class LoanProductData { final Map> accountingMappingOptions, final List accountingRuleOptions, final List valueConditionTypeOptions, final List daysInMonthTypeOptions, final List daysInYearTypeOptions, final List interestRecalculationCompoundingTypeOptions, - final List rescheduleStrategyTypeOptions) { + final List rescheduleStrategyTypeOptions, final List interestRecalculationFrequencyTypeOptions) { this.id = productData.id; this.name = productData.name; this.shortName = productData.shortName; @@ -526,6 +530,12 @@ public class LoanProductData { this.interestRecalculationCompoundingTypeOptions = interestRecalculationCompoundingTypeOptions; this.rescheduleStrategyTypeOptions = rescheduleStrategyTypeOptions; + if (CollectionUtils.isEmpty(interestRecalculationFrequencyTypeOptions)) { + this.interestRecalculationFrequencyTypeOptions = null; + } else { + this.interestRecalculationFrequencyTypeOptions = interestRecalculationFrequencyTypeOptions; + } + } private Collection nullIfEmpty(final Collection charges) { @@ -747,7 +757,8 @@ public class LoanProductData { final Long loanId = null; final CalendarData calendarData = null; return new LoanInterestRecalculationData(id, loanId, getInterestRecalculationCompoundingType(), getRescheduleStrategyType(), - calendarData); + calendarData, getRecalculationRestFrequencyType(), getRecalculationRestFrequencyInterval(), + getRecalculationRestFrequencyDate()); } private EnumOptionData getRescheduleStrategyType() { @@ -759,4 +770,19 @@ public class LoanProductData { if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getInterestRecalculationCompoundingType(); } return null; } + + private LocalDate getRecalculationRestFrequencyDate() { + if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationRestFrequencyDate(); } + return null; + } + + public EnumOptionData getRecalculationRestFrequencyType() { + if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationRestFrequencyType(); } + return null; + } + + public Integer getRecalculationRestFrequencyInterval() { + if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationRestFrequencyInterval(); } + return null; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductInterestRecalculationData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductInterestRecalculationData.java index 85786471b..c076b93c3 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductInterestRecalculationData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductInterestRecalculationData.java @@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.loanproduct.data; import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.interestRecalculationCompoundingType; import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.rescheduleStrategyType; +import org.joda.time.LocalDate; import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod; import org.mifosplatform.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod; @@ -20,13 +21,21 @@ public class LoanProductInterestRecalculationData { private final Long productId; private final EnumOptionData interestRecalculationCompoundingType; private final EnumOptionData rescheduleStrategyType; + private final EnumOptionData recalculationRestFrequencyType; + private final Integer recalculationRestFrequencyInterval; + private final LocalDate recalculationRestFrequencyDate; public LoanProductInterestRecalculationData(final Long id, final Long productId, - final EnumOptionData interestRecalculationCompoundingType, final EnumOptionData rescheduleStrategyType) { + final EnumOptionData interestRecalculationCompoundingType, final EnumOptionData rescheduleStrategyType, + final EnumOptionData recalculationRestFrequencyType, final Integer recalculationRestFrequencyInterval, + final LocalDate recalculationRestFrequencyDate) { this.id = id; this.productId = productId; this.interestRecalculationCompoundingType = interestRecalculationCompoundingType; this.rescheduleStrategyType = rescheduleStrategyType; + this.recalculationRestFrequencyType = recalculationRestFrequencyType; + this.recalculationRestFrequencyInterval = recalculationRestFrequencyInterval; + this.recalculationRestFrequencyDate = recalculationRestFrequencyDate; } public static LoanProductInterestRecalculationData sensibleDefaultsForNewLoanProductCreation() { @@ -34,7 +43,11 @@ public class LoanProductInterestRecalculationData { final Long productId = null; final EnumOptionData interestRecalculationCompoundingType = interestRecalculationCompoundingType(InterestRecalculationCompoundingMethod.NONE); final EnumOptionData rescheduleStrategyType = rescheduleStrategyType(LoanRescheduleStrategyMethod.REDUCE_EMI_AMOUNT); - return new LoanProductInterestRecalculationData(id, productId, interestRecalculationCompoundingType, rescheduleStrategyType); + final EnumOptionData recalculationRestFrequencyType = null; + final Integer recalculationRestFrequencyInterval = null; + final LocalDate recalculationRestFrequencyDate = null; + return new LoanProductInterestRecalculationData(id, productId, interestRecalculationCompoundingType, rescheduleStrategyType, + recalculationRestFrequencyType, recalculationRestFrequencyInterval, recalculationRestFrequencyDate); } public EnumOptionData getInterestRecalculationCompoundingType() { @@ -45,4 +58,16 @@ public class LoanProductInterestRecalculationData { return this.rescheduleStrategyType; } + public LocalDate getRecalculationRestFrequencyDate() { + return this.recalculationRestFrequencyDate; + } + + public EnumOptionData getRecalculationRestFrequencyType() { + return this.recalculationRestFrequencyType; + } + + public Integer getRecalculationRestFrequencyInterval() { + return this.recalculationRestFrequencyInterval; + } + } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java index f599cbe2c..b09f0cb47 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java @@ -43,7 +43,6 @@ import org.mifosplatform.portfolio.common.domain.DaysInMonthType; import org.mifosplatform.portfolio.common.domain.DaysInYearType; import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType; import org.mifosplatform.portfolio.fund.domain.Fund; -import org.mifosplatform.portfolio.loanaccount.domain.LoanInterestRecalculationDetails; import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator; import org.mifosplatform.portfolio.loanproduct.LoanProductConstants; import org.springframework.data.jpa.domain.AbstractPersistable; @@ -906,21 +905,7 @@ public class LoanProduct extends AbstractPersistable { return this.loanProductRelatedDetail.fetchDaysInYearType(); } - public LoanInterestRecalculationDetails copyInterestRecalculationSettings() { - LoanInterestRecalculationDetails loanInterestRecalculationDetails = null; - if (this.isInterestRecalculationEnabled()) { - loanInterestRecalculationDetails = LoanInterestRecalculationDetails.createFrom( - this.productInterestRecalculationDetails.getInterestRecalculationCompoundingMethod(), - this.productInterestRecalculationDetails.getRescheduleStrategyMethod()); - } - return loanInterestRecalculationDetails; - } - - public LoanInterestRecalculationDetails updateLoanInterestRecalculationDetails( - LoanInterestRecalculationDetails loanInterestRecalculationDetails) { - - loanInterestRecalculationDetails.update(this.productInterestRecalculationDetails.getInterestRecalculationCompoundingMethod(), - this.productInterestRecalculationDetails.getRescheduleStrategyMethod()); - return loanInterestRecalculationDetails; + public LoanProductInterestRecalculationDetails getProductInterestRecalculationDetails() { + return this.productInterestRecalculationDetails; } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductInterestRecalculationDetails.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductInterestRecalculationDetails.java index aa15e58f3..2d2f0a4d3 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductInterestRecalculationDetails.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductInterestRecalculationDetails.java @@ -5,6 +5,7 @@ */ package org.mifosplatform.portfolio.loanproduct.domain; +import java.util.Date; import java.util.Map; import javax.persistence.Column; @@ -12,7 +13,10 @@ import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.OneToOne; import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import org.joda.time.LocalDate; import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.portfolio.loanproduct.LoanProductConstants; import org.springframework.data.jpa.domain.AbstractPersistable; @@ -27,6 +31,7 @@ import org.springframework.data.jpa.domain.AbstractPersistable; @Table(name = "m_product_loan_recalculation_details") public class LoanProductInterestRecalculationDetails extends AbstractPersistable { + @SuppressWarnings("unused") @OneToOne @JoinColumn(name = "product_id", nullable = false) private LoanProduct loanProduct; @@ -43,6 +48,16 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable @Column(name = "reschedule_strategy_enum", nullable = false) private Integer rescheduleStrategyMethod; + @Column(name = "rest_frequency_type_enum", nullable = false) + private Integer restFrequencyType; + + @Column(name = "rest_frequency_interval", nullable = false) + private Integer restInterval; + + @Temporal(TemporalType.DATE) + @Column(name = "rest_freqency_date") + private Date restFrequencyDate; + protected LoanProductInterestRecalculationDetails() { // } @@ -55,13 +70,34 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable final Integer loanRescheduleStrategyMethod = LoanRescheduleStrategyMethod.fromInt( command.integerValueOfParameterNamed(LoanProductConstants.rescheduleStrategyMethodParameterName)).getValue(); - return new LoanProductInterestRecalculationDetails(interestRecalculationCompoundingMethod, loanRescheduleStrategyMethod); + final Integer recurrenceFrequency = command + .integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyTypeParameterName); + final LocalDate recurrenceOnLocalDate = command + .localDateValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName); + Integer recurrenceInterval = command + .integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyIntervalParameterName); + RecalculationFrequencyType frequencyType = RecalculationFrequencyType.fromInt(recurrenceFrequency); + Date recurrenceOnDate = null; + if (recurrenceOnLocalDate != null) { + if (frequencyType.isSameAsRepayment()) { + recurrenceInterval = 0; + } else { + recurrenceOnDate = recurrenceOnLocalDate.toDate(); + } + } + + return new LoanProductInterestRecalculationDetails(interestRecalculationCompoundingMethod, loanRescheduleStrategyMethod, + recurrenceFrequency, recurrenceInterval, recurrenceOnDate); } private LoanProductInterestRecalculationDetails(final Integer interestRecalculationCompoundingMethod, - final Integer rescheduleStrategyMethod) { + final Integer rescheduleStrategyMethod, final Integer restFrequencyType, final Integer restInterval, + final Date restFrequencyDate) { this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod; this.rescheduleStrategyMethod = rescheduleStrategyMethod; + this.restFrequencyType = restFrequencyType; + this.restInterval = restInterval; + this.restFrequencyDate = restFrequencyDate; } public void updateProduct(final LoanProduct loanProduct) { @@ -94,5 +130,60 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable actualChanges.put("locale", localeAsInput); this.rescheduleStrategyMethod = LoanRescheduleStrategyMethod.fromInt(newValue).getValue(); } + + if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyTypeParameterName, + this.restFrequencyType)) { + final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyTypeParameterName); + actualChanges.put(LoanProductConstants.recalculationRestFrequencyTypeParameterName, newValue); + actualChanges.put("locale", localeAsInput); + this.restFrequencyType = RecalculationFrequencyType.fromInt(newValue).getValue(); + } + RecalculationFrequencyType frequencyType = RecalculationFrequencyType.fromInt(this.restFrequencyType); + if (frequencyType.isSameAsRepayment()) { + this.restInterval = 0; + this.restFrequencyDate = null; + } else { + if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyIntervalParameterName, + this.restInterval)) { + Integer newValue = command + .integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyIntervalParameterName); + if (frequencyType.isSameAsRepayment()) { + newValue = 0; + } + actualChanges.put(LoanProductConstants.recalculationRestFrequencyIntervalParameterName, newValue); + actualChanges.put("locale", localeAsInput); + this.restInterval = newValue; + } + + if (command.isChangeInLocalDateParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName, + getRestFrequencyLocalDate())) { + final LocalDate newValue = command + .localDateValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName); + Date recurrenceOnDate = null; + if (newValue != null) { + if (!frequencyType.isSameAsRepayment()) { + recurrenceOnDate = newValue.toDate(); + } + } + actualChanges.put(LoanProductConstants.recalculationRestFrequencyDateParamName, newValue); + this.restFrequencyDate = recurrenceOnDate; + } + } + } + + public LocalDate getRestFrequencyLocalDate() { + LocalDate recurrenceOnLocalDate = null; + if (this.restFrequencyDate != null) { + recurrenceOnLocalDate = new LocalDate(this.restFrequencyDate); + } + return recurrenceOnLocalDate; + } + + public RecalculationFrequencyType getRestFrequencyType() { + return RecalculationFrequencyType.fromInt(this.restFrequencyType); + } + + public Integer getRestInterval() { + return this.restInterval; } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/RecalculationFrequencyType.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/RecalculationFrequencyType.java index 22a43a411..99188506d 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/RecalculationFrequencyType.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/RecalculationFrequencyType.java @@ -8,13 +8,14 @@ package org.mifosplatform.portfolio.loanproduct.domain; import java.util.HashMap; import java.util.Map; +import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType; + public enum RecalculationFrequencyType { INVALID(0, "interestRecalculationFrequencyType.invalid"), // SAME_AS_REPAYMENT_PERIOD(1, "interestRecalculationFrequencyType.same.as.repayment.period"), // DAILY(2, "interestRecalculationFrequencyType.daily"), // WEEKLY(3, "interestRecalculationFrequencyType.weekly"), // - FORTNIGHTLY(4, "interestRecalculationFrequencyType.fortnightly"), // - MONTHLY(5, "interestRecalculationFrequencyType.monthly"); + MONTHLY(4, "interestRecalculationFrequencyType.monthly"); private final Integer value; private final String code; @@ -44,4 +45,20 @@ public enum RecalculationFrequencyType { public String getCode() { return this.code; } + + public boolean isSameAsRepayment() { + return this.value.equals(RecalculationFrequencyType.SAME_AS_REPAYMENT_PERIOD.getValue()); + } + + public boolean isDaily() { + return this.value.equals(RecalculationFrequencyType.DAILY.getValue()); + } + + public boolean isWeekly() { + return this.value.equals(RecalculationFrequencyType.WEEKLY.getValue()); + } + + public boolean isMonthly() { + return this.value.equals(RecalculationFrequencyType.MONTHLY.getValue()); + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductDataValidator.java index 21c0dc690..3adebd408 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductDataValidator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductDataValidator.java @@ -16,6 +16,7 @@ import java.util.Map; import java.util.Set; import org.apache.commons.lang.StringUtils; +import org.joda.time.LocalDate; import org.mifosplatform.accounting.common.AccountingConstants.LOAN_PRODUCT_ACCOUNTING_PARAMS; import org.mifosplatform.accounting.common.AccountingRuleType; import org.mifosplatform.infrastructure.core.data.ApiParameterError; @@ -27,6 +28,7 @@ import org.mifosplatform.portfolio.loanproduct.LoanProductConstants; import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod; import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct; import org.mifosplatform.portfolio.loanproduct.domain.LoanProductValueConditionType; +import org.mifosplatform.portfolio.loanproduct.domain.RecalculationFrequencyType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -41,8 +43,8 @@ public final class LoanProductDataValidator { /** * The parameters supported for this command. */ - private final Set supportedParameters = new HashSet<>(Arrays.asList("locale", "dateFormat", "name", "description", - "fundId", "currencyCode", "digitsAfterDecimal", "inMultiplesOf", "principal", "minPrincipal", "maxPrincipal", "repaymentEvery", + private final Set supportedParameters = new HashSet<>(Arrays.asList("locale", "dateFormat", "name", "description", "fundId", + "currencyCode", "digitsAfterDecimal", "inMultiplesOf", "principal", "minPrincipal", "maxPrincipal", "repaymentEvery", "numberOfRepayments", "minNumberOfRepayments", "maxNumberOfRepayments", "repaymentFrequencyType", "interestRatePerPeriod", "minInterestRatePerPeriod", "maxInterestRatePerPeriod", "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", "inArrearsTolerance", "transactionProcessingStrategyId", "graceOnPrincipalPayment", @@ -54,7 +56,8 @@ public final class LoanProductDataValidator { LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.FEE_INCOME_ACCOUNT_MAPPING.getValue(),LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_RECOVERY.getValue(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.FEE_INCOME_ACCOUNT_MAPPING.getValue(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_RECOVERY.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTY_INCOME_ACCOUNT_MAPPING.getValue(), LoanProductConstants.useBorrowerCycleParameterName, LoanProductConstants.principalVariationsForBorrowerCycleParameterName, LoanProductConstants.interestRateVariationsForBorrowerCycleParameterName, @@ -64,7 +67,10 @@ public final class LoanProductDataValidator { LoanProductConstants.overdueDaysForNPAParameterName, LoanProductConstants.isInterestRecalculationEnabledParameterName, LoanProductConstants.daysInYearTypeParameterName, LoanProductConstants.daysInMonthTypeParameterName, LoanProductConstants.rescheduleStrategyMethodParameterName, - LoanProductConstants.interestRecalculationCompoundingMethodParameterName)); + LoanProductConstants.interestRecalculationCompoundingMethodParameterName, + LoanProductConstants.recalculationRestFrequencyDateParamName, + LoanProductConstants.recalculationRestFrequencyIntervalParameterName, + LoanProductConstants.recalculationRestFrequencyTypeParameterName)); private final FromJsonHelper fromApiJsonHelper; @@ -129,18 +135,18 @@ public final class LoanProductDataValidator { baseDataValidator.reset().parameter(maxPrincipalParameterName).value(maxPrincipalAmount).ignoreIfNull().positiveAmount(); } - if (maxPrincipalAmount != null && maxPrincipalAmount.compareTo(BigDecimal.ZERO) != -1 ) { + if (maxPrincipalAmount != null && maxPrincipalAmount.compareTo(BigDecimal.ZERO) != -1) { if (minPrincipalAmount != null && minPrincipalAmount.compareTo(BigDecimal.ZERO) != -1) { baseDataValidator.reset().parameter(maxPrincipalParameterName).value(maxPrincipalAmount).notLessThanMin(minPrincipalAmount); - if (minPrincipalAmount.compareTo(maxPrincipalAmount) <= 0 && principal != null ) { + if (minPrincipalAmount.compareTo(maxPrincipalAmount) <= 0 && principal != null) { baseDataValidator.reset().parameter("principal").value(principal) .inMinAndMaxAmountRange(minPrincipalAmount, maxPrincipalAmount); } - } else if(principal != null) { + } else if (principal != null) { baseDataValidator.reset().parameter("principal").value(principal).notGreaterThanMax(maxPrincipalAmount); } - } else if (minPrincipalAmount != null && minPrincipalAmount.compareTo(BigDecimal.ZERO) != -1 && principal !=null) { + } else if (minPrincipalAmount != null && minPrincipalAmount.compareTo(BigDecimal.ZERO) != -1 && principal != null) { baseDataValidator.reset().parameter("principal").value(principal).notLessThanMin(minPrincipalAmount); } @@ -291,7 +297,7 @@ public final class LoanProductDataValidator { if (isInterestRecalculationEnabled != null) { if (isInterestRecalculationEnabled.booleanValue()) { - validateInterestRecalculationParams(element, baseDataValidator); + validateInterestRecalculationParams(element, baseDataValidator, null); } } @@ -333,8 +339,8 @@ public final class LoanProductDataValidator { final Long incomeFromRecoveryAccountId = this.fromApiJsonHelper.extractLongNamed( LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_RECOVERY.getValue(), element); - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_RECOVERY.getValue()).value(incomeFromRecoveryAccountId) - .notNull().integerGreaterThanZero(); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_RECOVERY.getValue()) + .value(incomeFromRecoveryAccountId).notNull().integerGreaterThanZero(); final Long writeOffAccountId = this.fromApiJsonHelper.extractLongNamed( LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), element); @@ -411,23 +417,67 @@ public final class LoanProductDataValidator { } } - private void validateInterestRecalculationParams(final JsonElement element, final DataValidatorBuilder baseDataValidator) { + private void validateInterestRecalculationParams(final JsonElement element, final DataValidatorBuilder baseDataValidator, + final LoanProduct loanProduct) { /** * { @link InterestRecalculationCompoundingMethod } */ - final Integer interestRecalculationCompoundingMethod = this.fromApiJsonHelper.extractIntegerNamed( - LoanProductConstants.interestRecalculationCompoundingMethodParameterName, element, Locale.getDefault()); - baseDataValidator.reset().parameter(LoanProductConstants.interestRecalculationCompoundingMethodParameterName) - .value(interestRecalculationCompoundingMethod).notNull().inMinMaxRange(0, 3); - + if (loanProduct == null + || this.fromApiJsonHelper + .parameterExists(LoanProductConstants.interestRecalculationCompoundingMethodParameterName, element)) { + final Integer interestRecalculationCompoundingMethod = this.fromApiJsonHelper.extractIntegerNamed( + LoanProductConstants.interestRecalculationCompoundingMethodParameterName, element, Locale.getDefault()); + baseDataValidator.reset().parameter(LoanProductConstants.interestRecalculationCompoundingMethodParameterName) + .value(interestRecalculationCompoundingMethod).notNull().inMinMaxRange(0, 3); + } /** * { @link LoanRescheduleStrategyMethod } */ - final Integer rescheduleStrategyMethod = this.fromApiJsonHelper.extractIntegerNamed( - LoanProductConstants.rescheduleStrategyMethodParameterName, element, Locale.getDefault()); - baseDataValidator.reset().parameter(LoanProductConstants.rescheduleStrategyMethodParameterName).value(rescheduleStrategyMethod) - .notNull().inMinMaxRange(1, 3); + if (loanProduct == null + || this.fromApiJsonHelper.parameterExists(LoanProductConstants.rescheduleStrategyMethodParameterName, element)) { + final Integer rescheduleStrategyMethod = this.fromApiJsonHelper.extractIntegerNamed( + LoanProductConstants.rescheduleStrategyMethodParameterName, element, Locale.getDefault()); + baseDataValidator.reset().parameter(LoanProductConstants.rescheduleStrategyMethodParameterName).value(rescheduleStrategyMethod) + .notNull().inMinMaxRange(1, 3); + } + + RecalculationFrequencyType frequencyType = null; + + if (loanProduct == null + || this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationRestFrequencyTypeParameterName, element)) { + final Integer recalculationRestFrequencyType = this.fromApiJsonHelper.extractIntegerNamed( + LoanProductConstants.recalculationRestFrequencyTypeParameterName, element, Locale.getDefault()); + baseDataValidator.reset().parameter(LoanProductConstants.recalculationRestFrequencyTypeParameterName) + .value(recalculationRestFrequencyType).notNull().inMinMaxRange(1, 4); + frequencyType = RecalculationFrequencyType.fromInt(recalculationRestFrequencyType); + } + + if (frequencyType == null) { + if (loanProduct == null) { + frequencyType = RecalculationFrequencyType.INVALID; + } else { + frequencyType = loanProduct.getProductInterestRecalculationDetails().getRestFrequencyType(); + } + } + + if (!frequencyType.isSameAsRepayment()) { + if (loanProduct == null + || this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationRestFrequencyDateParamName, element)) { + final LocalDate recurrenceOnLocalDate = this.fromApiJsonHelper.extractLocalDateNamed( + LoanProductConstants.recalculationRestFrequencyDateParamName, element); + baseDataValidator.reset().parameter(LoanProductConstants.recalculationRestFrequencyDateParamName) + .value(recurrenceOnLocalDate).notNull(); + } + if (loanProduct == null + || this.fromApiJsonHelper + .parameterExists(LoanProductConstants.recalculationRestFrequencyIntervalParameterName, element)) { + final Integer recurrenceInterval = this.fromApiJsonHelper.extractIntegerNamed( + LoanProductConstants.recalculationRestFrequencyIntervalParameterName, element, Locale.getDefault()); + baseDataValidator.reset().parameter(LoanProductConstants.recalculationRestFrequencyIntervalParameterName) + .value(recurrenceInterval).notNull(); + } + } } @@ -654,7 +704,7 @@ public final class LoanProductDataValidator { if (isInterestRecalculationEnabled != null) { if (isInterestRecalculationEnabled.booleanValue()) { - validateInterestRecalculationParams(element, baseDataValidator); + validateInterestRecalculationParams(element, baseDataValidator, loanProduct); } } } @@ -693,8 +743,8 @@ public final class LoanProductDataValidator { final Long incomeFromRecoveryAccountId = this.fromApiJsonHelper.extractLongNamed( LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_RECOVERY.getValue(), element); - baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_RECOVERY.getValue()).value(incomeFromRecoveryAccountId) - .ignoreIfNull().integerGreaterThanZero(); + baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_RECOVERY.getValue()) + .value(incomeFromRecoveryAccountId).ignoreIfNull().integerGreaterThanZero(); final Long writeOffAccountId = this.fromApiJsonHelper.extractLongNamed( LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), element); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java index f9e929865..037c4432f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java @@ -141,12 +141,11 @@ public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlat @Override public List retrieveInterestRecalculationFrequencyTypeOptions() { - + final List interestRecalculationFrequencyTypeOptions = Arrays.asList( interestRecalculationFrequencyType(RecalculationFrequencyType.SAME_AS_REPAYMENT_PERIOD), interestRecalculationFrequencyType(RecalculationFrequencyType.DAILY), interestRecalculationFrequencyType(RecalculationFrequencyType.WEEKLY), - interestRecalculationFrequencyType(RecalculationFrequencyType.FORTNIGHTLY), interestRecalculationFrequencyType(RecalculationFrequencyType.MONTHLY)); return interestRecalculationFrequencyTypeOptions; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java index d0f8b0460..6e3d2fd05 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java @@ -526,10 +526,6 @@ public class LoanEnumerations { optionData = new EnumOptionData(RecalculationFrequencyType.DAILY.getValue().longValue(), RecalculationFrequencyType.DAILY.getCode(), "Daily"); break; - case FORTNIGHTLY: - optionData = new EnumOptionData(RecalculationFrequencyType.FORTNIGHTLY.getValue().longValue(), - RecalculationFrequencyType.FORTNIGHTLY.getCode(), "Fortnightly"); - break; case MONTHLY: optionData = new EnumOptionData(RecalculationFrequencyType.MONTHLY.getValue().longValue(), RecalculationFrequencyType.MONTHLY.getCode(), "Monthly"); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java index 4c71b2666..ac781d76b 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java @@ -125,6 +125,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo + "lp.allow_multiple_disbursals as multiDisburseLoan, lp.max_disbursals as maxTrancheCount, lp.max_outstanding_loan_balance as outstandingLoanBalance, " + "lp.days_in_month_enum as daysInMonth, lp.days_in_year_enum as daysInYear, lp.interest_recalculation_enabled as isInterestRecalculationEnabled, " + "lpr.id as lprId, lpr.product_id as productId, lpr.compound_type_enum as compoundType, lpr.reschedule_strategy_enum as rescheduleStrategy, " + + "lpr.rest_frequency_type_enum as restFrequencyEnum, lpr.rest_frequency_interval as restFrequencyInterval, " + + "lpr.rest_freqency_date as restFrequencyDate, " + "curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol, lp.external_id as externalId " + " from m_product_loan lp " + " left join m_fund f on f.id = lp.fund_id " @@ -242,9 +244,14 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo .interestRecalculationCompoundingType(compoundTypeEnumValue); final int rescheduleStrategyEnumValue = JdbcSupport.getInteger(rs, "rescheduleStrategy"); final EnumOptionData rescheduleStrategyType = LoanEnumerations.rescheduleStrategyType(rescheduleStrategyEnumValue); + final int restFrequencyEnumValue = JdbcSupport.getInteger(rs, "restFrequencyEnum"); + final EnumOptionData restFrequencyType = LoanEnumerations.interestRecalculationFrequencyType(restFrequencyEnumValue); + final int restFrequencyInterval = JdbcSupport.getInteger(rs, "restFrequencyInterval"); + final LocalDate restFrequencyDate = JdbcSupport.getLocalDate(rs, "restFrequencyDate"); interestRecalculationData = new LoanProductInterestRecalculationData(lprId, productId, - interestRecalculationCompoundingType, rescheduleStrategyType); + interestRecalculationCompoundingType, rescheduleStrategyType, restFrequencyType, restFrequencyInterval, + restFrequencyDate); } return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, From 5fc958f2bc084f7073bae1837ddb92300f650727 Mon Sep 17 00:00:00 2001 From: Pramod Nuthakki Date: Wed, 3 Sep 2014 17:03:40 +0530 Subject: [PATCH 2/2] corrected junits --- .../common/loans/LoanApplicationTestBuilder.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanApplicationTestBuilder.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanApplicationTestBuilder.java index de5bed65a..8b8dfaefb 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanApplicationTestBuilder.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanApplicationTestBuilder.java @@ -42,7 +42,6 @@ public class LoanApplicationTestBuilder { private String loanType = "individual"; private String fixedEmiAmount = "10000"; private String maxOutstandingLoanBalance = "36000"; - private String recalculationFrequencyType = "1"; private String graceOnPrincipalPayment = null; private List disbursementData = null; private List charges = new ArrayList(); @@ -72,7 +71,6 @@ public class LoanApplicationTestBuilder { map.put("expectedDisbursementDate", this.expectedDisbursmentDate); map.put("submittedOnDate", this.submittedOnDate); map.put("loanType", this.loanType); - map.put("recalculationFrequencyType", this.recalculationFrequencyType); if (charges != null) { map.put("charges", charges); }