MIFOSX-282:added min and max constraints for Interest rate and number of repayments

This commit is contained in:
ashok-conflux
2013-04-05 20:24:40 +05:30
parent c28ad6b18c
commit 2446a0f05e
16 changed files with 687 additions and 102 deletions
@@ -0,0 +1,37 @@
ALTER TABLE `m_product_loan`
ADD COLUMN `min_nominal_interest_rate_per_period` DECIMAL(19,6) NOT NULL AFTER `nominal_interest_rate_per_period`,
ADD COLUMN `max_nominal_interest_rate_per_period` DECIMAL(19,6) NOT NULL AFTER `min_nominal_interest_rate_per_period`,
ADD COLUMN `min_number_of_repayments` SMALLINT(5) NOT NULL AFTER `number_of_repayments`,
ADD COLUMN `max_number_of_repayments` SMALLINT(5) NOT NULL AFTER `min_number_of_repayments`;
ALTER TABLE `m_loan`
ADD COLUMN `min_nominal_interest_rate_per_period` DECIMAL(19,6) NOT NULL AFTER `nominal_interest_rate_per_period`,
ADD COLUMN `max_nominal_interest_rate_per_period` DECIMAL(19,6) NOT NULL AFTER `min_nominal_interest_rate_per_period`,
ADD COLUMN `min_number_of_repayments` SMALLINT(5) NOT NULL AFTER `number_of_repayments`,
ADD COLUMN `max_number_of_repayments` SMALLINT(5) NOT NULL AFTER `min_number_of_repayments`;
ALTER TABLE `m_loan`
ALTER `min_principal_amount` DROP DEFAULT,
ALTER `max_principal_amount` DROP DEFAULT;
ALTER TABLE `m_loan`
CHANGE COLUMN `min_principal_amount` `min_principal_amount` DECIMAL(19,6) NULL AFTER `principal_amount`,
CHANGE COLUMN `max_principal_amount` `max_principal_amount` DECIMAL(19,6) NULL AFTER `min_principal_amount`,
CHANGE COLUMN `min_nominal_interest_rate_per_period` `min_nominal_interest_rate_per_period` DECIMAL(19,6) NULL AFTER `nominal_interest_rate_per_period`,
CHANGE COLUMN `max_nominal_interest_rate_per_period` `max_nominal_interest_rate_per_period` DECIMAL(19,6) NULL AFTER `min_nominal_interest_rate_per_period`,
CHANGE COLUMN `min_number_of_repayments` `min_number_of_repayments` SMALLINT(5) NULL AFTER `number_of_repayments`,
CHANGE COLUMN `max_number_of_repayments` `max_number_of_repayments` SMALLINT(5) NULL AFTER `min_number_of_repayments`;
ALTER TABLE `m_product_loan`
ALTER `min_principal_amount` DROP DEFAULT,
ALTER `max_principal_amount` DROP DEFAULT,
ALTER `min_nominal_interest_rate_per_period` DROP DEFAULT,
ALTER `max_nominal_interest_rate_per_period` DROP DEFAULT,
ALTER `min_number_of_repayments` DROP DEFAULT,
ALTER `max_number_of_repayments` DROP DEFAULT;
ALTER TABLE `m_product_loan`
CHANGE COLUMN `min_principal_amount` `min_principal_amount` DECIMAL(19,6) NULL AFTER `principal_amount`,
CHANGE COLUMN `max_principal_amount` `max_principal_amount` DECIMAL(19,6) NULL AFTER `min_principal_amount`,
CHANGE COLUMN `min_nominal_interest_rate_per_period` `min_nominal_interest_rate_per_period` DECIMAL(19,6) NULL AFTER `nominal_interest_rate_per_period`,
CHANGE COLUMN `max_nominal_interest_rate_per_period` `max_nominal_interest_rate_per_period` DECIMAL(19,6) NULL AFTER `min_nominal_interest_rate_per_period`,
CHANGE COLUMN `min_number_of_repayments` `min_number_of_repayments` SMALLINT(5) NULL AFTER `number_of_repayments`,
CHANGE COLUMN `max_number_of_repayments` `max_number_of_repayments` SMALLINT(5) NULL AFTER `min_number_of_repayments`;
@@ -290,6 +290,19 @@ public final class JsonCommand {
return isChanged; return isChanged;
} }
public boolean isChangeInBigDecimalParameterNamedWithNullCheck(final String parameterName, final BigDecimal existingValue) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final BigDecimal workingValue = bigDecimalValueOfParameterNamed(parameterName);
if(workingValue == null && existingValue != null){
isChanged = true;
}else{
isChanged = differenceExists(existingValue, workingValue);
}
}
return isChanged;
}
public BigDecimal bigDecimalValueOfParameterNamed(final String parameterName) { public BigDecimal bigDecimalValueOfParameterNamed(final String parameterName) {
return this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(parameterName, parsedCommand); return this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(parameterName, parsedCommand);
} }
@@ -303,6 +316,19 @@ public final class JsonCommand {
return isChanged; return isChanged;
} }
public boolean isChangeInIntegerParameterNamedWithNullCheck(final String parameterName, final Integer existingValue) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final Integer workingValue = integerValueOfParameterNamed(parameterName);
if(workingValue == null && existingValue != null){
isChanged = true;
}else{
isChanged = differenceExists(existingValue, workingValue);
}
}
return isChanged;
}
public Integer integerValueOfParameterNamed(final String parameterName) { public Integer integerValueOfParameterNamed(final String parameterName) {
return this.fromApiJsonHelper.extractIntegerWithLocaleNamed(parameterName, parsedCommand); return this.fromApiJsonHelper.extractIntegerWithLocaleNamed(parameterName, parsedCommand);
} }
@@ -389,6 +389,40 @@ public class DataValidatorBuilder {
return this; return this;
} }
public DataValidatorBuilder notLessThanMin(final BigDecimal min) {
if (min != null && value != null){
BigDecimal amount = BigDecimal.valueOf(Double.valueOf(value.toString()));
if (amount.compareTo(min) == -1) {
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter)
.append(".is.less.than.min");
StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(parameter) .append(" value ").append(amount)
.append(" must not be less than minimum value ").append(min);
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), parameter, amount, min);
dataValidationErrors.add(error);
return this;
}
}
return this;
}
public DataValidatorBuilder notGreaterThanMax(final BigDecimal max) {
if (max != null && value != null){
BigDecimal amount = BigDecimal.valueOf(Double.valueOf(value.toString()));
if (amount.compareTo(max) == 1) {
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter)
.append(".is.greater.than.max");
StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(parameter) .append(" value ").append(amount)
.append(" must not be more than maximum value ").append(max);
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), parameter, amount, max);
dataValidationErrors.add(error);
return this;
}
}
return this;
}
public DataValidatorBuilder comapareMinAndMaxOfTwoBigDecmimalNos(final BigDecimal min, final BigDecimal max) { public DataValidatorBuilder comapareMinAndMaxOfTwoBigDecmimalNos(final BigDecimal min, final BigDecimal max) {
if (min != null && max != null) if (min != null && max != null)
if (max.compareTo(min) == -1) { if (max.compareTo(min) == -1) {
@@ -423,4 +457,40 @@ public class DataValidatorBuilder {
} }
return this; return this;
} }
public DataValidatorBuilder notLessThanMin(final Integer min) {
if (value == null && ignoreNullValue) { return this; }
if (value != null && min != null) {
Integer number = Integer.valueOf(value.toString());
if (number < min) {
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter)
.append(".is.less.than.min");
StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(parameter)
.append(" must be greater than minimum value ").append(min);
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), parameter, number, min);
dataValidationErrors.add(error);
}
}
return this;
}
public DataValidatorBuilder notGreaterThanMax(final Integer max) {
if (value == null && ignoreNullValue) { return this; }
if (value != null && max != null) {
Integer number = Integer.valueOf(value.toString());
if (number > max) {
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter)
.append(".is.greater.than.max");
StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(parameter)
.append(" must be less than maximum value ").append(max);
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), parameter, number, max);
dataValidationErrors.add(error);
}
}
return this;
}
} }
@@ -1321,6 +1321,8 @@ public class Loan extends AbstractPersistable<Long> {
final BigDecimal maxPrincipal = this.loanRepaymentScheduleDetail.getMaxPrincipal().getAmount(); final BigDecimal maxPrincipal = this.loanRepaymentScheduleDetail.getMaxPrincipal().getAmount();
final BigDecimal inArrearsTolerance = this.loanRepaymentScheduleDetail.getInArrearsTolerance().getAmount(); final BigDecimal inArrearsTolerance = this.loanRepaymentScheduleDetail.getInArrearsTolerance().getAmount();
final BigDecimal interestRatePerPeriod = this.loanRepaymentScheduleDetail.getNominalInterestRatePerPeriod(); final BigDecimal interestRatePerPeriod = this.loanRepaymentScheduleDetail.getNominalInterestRatePerPeriod();
final BigDecimal minInterestRatePerPeriod = this.loanRepaymentScheduleDetail.getMinNominalInterestRatePerPeriod();
final BigDecimal maxInterestRatePerPeriod = this.loanRepaymentScheduleDetail.getMaxNominalInterestRatePerPeriod();
final PeriodFrequencyType interestRatePeriodFrequencyType = this.loanRepaymentScheduleDetail.getInterestPeriodFrequencyType(); final PeriodFrequencyType interestRatePeriodFrequencyType = this.loanRepaymentScheduleDetail.getInterestPeriodFrequencyType();
final BigDecimal defaultAnnualNominalInterestRate = this.loanRepaymentScheduleDetail.getAnnualNominalInterestRate(); final BigDecimal defaultAnnualNominalInterestRate = this.loanRepaymentScheduleDetail.getAnnualNominalInterestRate();
@@ -1329,13 +1331,16 @@ public class Loan extends AbstractPersistable<Long> {
final Integer repaymentEvery = this.loanRepaymentScheduleDetail.getRepayEvery(); final Integer repaymentEvery = this.loanRepaymentScheduleDetail.getRepayEvery();
final PeriodFrequencyType repaymentPeriodFrequencyType = this.loanRepaymentScheduleDetail.getRepaymentPeriodFrequencyType(); final PeriodFrequencyType repaymentPeriodFrequencyType = this.loanRepaymentScheduleDetail.getRepaymentPeriodFrequencyType();
final Integer numberOfRepayments = this.loanRepaymentScheduleDetail.getNumberOfRepayments(); final Integer numberOfRepayments = this.loanRepaymentScheduleDetail.getNumberOfRepayments();
final Integer minNumberOfRepayments = this.loanRepaymentScheduleDetail.getMinNumberOfRepayments();
final Integer maxNumberOfRepayments = this.loanRepaymentScheduleDetail.getMaxNumberOfRepayments();
final AmortizationMethod amortizationMethod = this.loanRepaymentScheduleDetail.getAmortizationMethod(); final AmortizationMethod amortizationMethod = this.loanRepaymentScheduleDetail.getAmortizationMethod();
final Integer loanTermFrequency = this.termFrequency; final Integer loanTermFrequency = this.termFrequency;
final PeriodFrequencyType loanTermPeriodFrequencyType = PeriodFrequencyType.fromInt(this.termPeriodFrequencyType); final PeriodFrequencyType loanTermPeriodFrequencyType = PeriodFrequencyType.fromInt(this.termPeriodFrequencyType);
final LoanSchedule loanSchedule = new LoanSchedule(loanScheduleGenerator, applicationCurrency, principal, minPrincipal, final LoanSchedule loanSchedule = new LoanSchedule(loanScheduleGenerator, applicationCurrency, principal, minPrincipal,
maxPrincipal, interestRatePerPeriod, interestRatePeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestRatePeriodFrequencyType,
interestCalculationPeriodMethod, repaymentEvery, repaymentPeriodFrequencyType, numberOfRepayments, amortizationMethod, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery,
repaymentPeriodFrequencyType, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, amortizationMethod,
loanTermFrequency, loanTermPeriodFrequencyType, setOfLoanCharges(), this.getDisbursementDate(), loanTermFrequency, loanTermPeriodFrequencyType, setOfLoanCharges(), this.getDisbursementDate(),
this.getExpectedFirstRepaymentOnDate(), this.getInterestChargedFromDate(), inArrearsTolerance); this.getExpectedFirstRepaymentOnDate(), this.getInterestChargedFromDate(), inArrearsTolerance);
@@ -30,6 +30,8 @@ public final class LoanSchedule {
private final BigDecimal minPrincipal; private final BigDecimal minPrincipal;
private final BigDecimal maxPrincipal; private final BigDecimal maxPrincipal;
private final BigDecimal nominalInterestRatePerPeriod; private final BigDecimal nominalInterestRatePerPeriod;
private final BigDecimal minNominalInterestRatePerPeriod;
private final BigDecimal maxNominalInterestRatePerPeriod;
private final PeriodFrequencyType interestRatePeriodFrequencyType; private final PeriodFrequencyType interestRatePeriodFrequencyType;
private final BigDecimal nominalAnnualInterestRate; private final BigDecimal nominalAnnualInterestRate;
private final InterestMethod interestMethod; private final InterestMethod interestMethod;
@@ -37,6 +39,8 @@ public final class LoanSchedule {
private final Integer repaymentEvery; private final Integer repaymentEvery;
private final PeriodFrequencyType repaymentPeriodFrequencyType; private final PeriodFrequencyType repaymentPeriodFrequencyType;
private final Integer numberOfRepayments; private final Integer numberOfRepayments;
private final Integer minNumberOfRepayments;
private final Integer maxNumberOfRepayments;
private final AmortizationMethod amortizationMethod; private final AmortizationMethod amortizationMethod;
private final Integer loanTermFrequency; private final Integer loanTermFrequency;
private final PeriodFrequencyType loanTermPeriodFrequencyType; private final PeriodFrequencyType loanTermPeriodFrequencyType;
@@ -49,10 +53,10 @@ public final class LoanSchedule {
public LoanSchedule(final LoanScheduleGenerator loanScheduleGenerator, final ApplicationCurrency applicationCurrency, public LoanSchedule(final LoanScheduleGenerator loanScheduleGenerator, final ApplicationCurrency applicationCurrency,
final BigDecimal principal, final BigDecimal minPrincipal, final BigDecimal maxPrincipal, final BigDecimal principal, final BigDecimal minPrincipal, final BigDecimal maxPrincipal,
final BigDecimal nominalInterestRatePerPeriod, final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal nominalInterestRatePerPeriod, final BigDecimal minNominalInterestRatePerPeriod, final BigDecimal maxNominalInterestRatePerPeriod, final PeriodFrequencyType interestRatePeriodFrequencyType,
final BigDecimal nominalAnnualInterestRate, final InterestMethod interestMethod, final BigDecimal nominalAnnualInterestRate, final InterestMethod interestMethod,
final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Integer repaymentEvery, final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Integer repaymentEvery,
final PeriodFrequencyType repaymentPeriodFrequencyType, final Integer numberOfRepayments, final PeriodFrequencyType repaymentPeriodFrequencyType, final Integer numberOfRepayments, final Integer minNumberOfRepayments, final Integer maxNumberOfRepayments,
final AmortizationMethod amortizationMethod, final Integer loanTermFrequency, final AmortizationMethod amortizationMethod, final Integer loanTermFrequency,
final PeriodFrequencyType loanTermPeriodFrequencyType, final Set<LoanCharge> loanCharges, final LocalDate disbursementDate, final PeriodFrequencyType loanTermPeriodFrequencyType, final Set<LoanCharge> loanCharges, final LocalDate disbursementDate,
final LocalDate repaymentStartFromDate, final LocalDate interestChargedFromDate, final BigDecimal inArrearsTolerance) { final LocalDate repaymentStartFromDate, final LocalDate interestChargedFromDate, final BigDecimal inArrearsTolerance) {
@@ -62,6 +66,8 @@ public final class LoanSchedule {
this.minPrincipal = minPrincipal; this.minPrincipal = minPrincipal;
this.maxPrincipal = maxPrincipal; this.maxPrincipal = maxPrincipal;
this.nominalInterestRatePerPeriod = nominalInterestRatePerPeriod; this.nominalInterestRatePerPeriod = nominalInterestRatePerPeriod;
this.minNominalInterestRatePerPeriod = minNominalInterestRatePerPeriod;
this.maxNominalInterestRatePerPeriod = maxNominalInterestRatePerPeriod;
this.interestRatePeriodFrequencyType = interestRatePeriodFrequencyType; this.interestRatePeriodFrequencyType = interestRatePeriodFrequencyType;
this.nominalAnnualInterestRate = nominalAnnualInterestRate; this.nominalAnnualInterestRate = nominalAnnualInterestRate;
this.interestMethod = interestMethod; this.interestMethod = interestMethod;
@@ -69,6 +75,8 @@ public final class LoanSchedule {
this.repaymentEvery = repaymentEvery; this.repaymentEvery = repaymentEvery;
this.repaymentPeriodFrequencyType = repaymentPeriodFrequencyType; this.repaymentPeriodFrequencyType = repaymentPeriodFrequencyType;
this.numberOfRepayments = numberOfRepayments; this.numberOfRepayments = numberOfRepayments;
this.minNumberOfRepayments = minNumberOfRepayments;
this.maxNumberOfRepayments = maxNumberOfRepayments;
this.amortizationMethod = amortizationMethod; this.amortizationMethod = amortizationMethod;
this.loanTermFrequency = loanTermFrequency; this.loanTermFrequency = loanTermFrequency;
this.loanTermPeriodFrequencyType = loanTermPeriodFrequencyType; this.loanTermPeriodFrequencyType = loanTermPeriodFrequencyType;
@@ -87,9 +95,9 @@ public final class LoanSchedule {
public LoanProductRelatedDetail loanProductRelatedDetail() { public LoanProductRelatedDetail loanProductRelatedDetail() {
final MonetaryCurrency currency = new MonetaryCurrency(applicationCurrency.getCode(), applicationCurrency.getDecimalPlaces()); final MonetaryCurrency currency = new MonetaryCurrency(applicationCurrency.getCode(), applicationCurrency.getDecimalPlaces());
return LoanProductRelatedDetail.createFrom(currency, principal, minPrincipal, maxPrincipal, nominalInterestRatePerPeriod, return LoanProductRelatedDetail.createFrom(currency, principal, minPrincipal, maxPrincipal, nominalInterestRatePerPeriod, minNominalInterestRatePerPeriod, maxNominalInterestRatePerPeriod,
interestRatePeriodFrequencyType, nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod, interestRatePeriodFrequencyType, nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod,
repaymentEvery, repaymentPeriodFrequencyType, numberOfRepayments, amortizationMethod, this.inArrearsTolerance); repaymentEvery, repaymentPeriodFrequencyType, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, amortizationMethod, this.inArrearsTolerance);
} }
public Integer getLoanTermFrequency() { public Integer getLoanTermFrequency() {
@@ -75,6 +75,8 @@ public class LoanScheduleAssembler {
final BigDecimal minPrincipal = loanProduct.getMinPrincipalAmount().getAmount();//Copy minPrincipal from loan product to loan final BigDecimal minPrincipal = loanProduct.getMinPrincipalAmount().getAmount();//Copy minPrincipal from loan product to loan
final BigDecimal maxPrincipal = loanProduct.getMaxPrincipalAmount().getAmount();//Copy maxPrincipal from loan product to loan final BigDecimal maxPrincipal = loanProduct.getMaxPrincipalAmount().getAmount();//Copy maxPrincipal from loan product to loan
final BigDecimal interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element); final BigDecimal interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element);
final BigDecimal minInterestRatePerPeriod = loanProduct.getMinNominalInterestRatePerPeriod();//Copy from Loan product to Loan
final BigDecimal maxInterestRatePerPeriod = loanProduct.getMaxNominalInterestRatePerPeriod();//Copy from Loan product to Loan
final Integer interestRateFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestRateFrequencyType", element); final Integer interestRateFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestRateFrequencyType", element);
final Integer interestType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestType", element); final Integer interestType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestType", element);
final Integer interestCalculationPeriodType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestCalculationPeriodType", final Integer interestCalculationPeriodType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestCalculationPeriodType",
@@ -91,6 +93,8 @@ public class LoanScheduleAssembler {
final Integer repaymentEvery = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentEvery", element); final Integer repaymentEvery = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentEvery", element);
final Integer repaymentFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentFrequencyType", element); final Integer repaymentFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentFrequencyType", element);
final Integer numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed("numberOfRepayments", element); final Integer numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed("numberOfRepayments", element);
final Integer minNumberOfRepayments = loanProduct.getMinNumberOfRepayments();//Copy from Loan product to Loan
final Integer maxNumberOfRepayments = loanProduct.getMaxNumberOfRepayments();//Copy from Loan product to Loan
final Integer amortizationType = fromApiJsonHelper.extractIntegerWithLocaleNamed("amortizationType", element); final Integer amortizationType = fromApiJsonHelper.extractIntegerWithLocaleNamed("amortizationType", element);
final PeriodFrequencyType repaymentPeriodFrequencyType = PeriodFrequencyType.fromInt(repaymentFrequencyType); final PeriodFrequencyType repaymentPeriodFrequencyType = PeriodFrequencyType.fromInt(repaymentFrequencyType);
final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(amortizationType); final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(amortizationType);
@@ -107,9 +111,9 @@ public class LoanScheduleAssembler {
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(interestMethod); final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(interestMethod);
return new LoanSchedule(loanScheduleGenerator, applicationCurrency, principal, minPrincipal, maxPrincipal, interestRatePerPeriod, return new LoanSchedule(loanScheduleGenerator, applicationCurrency, principal, minPrincipal, maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod,
interestRatePeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, interestRatePeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod,
repaymentEvery, repaymentPeriodFrequencyType, numberOfRepayments, amortizationMethod, loanTermFrequency, repaymentEvery, repaymentPeriodFrequencyType, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, amortizationMethod, loanTermFrequency,
loanTermPeriodFrequencyType, loanCharges, expectedDisbursementDate, repaymentsStartingFromDate, interestChargedFromDate, inArrearsTolerance); loanTermPeriodFrequencyType, loanCharges, expectedDisbursementDate, repaymentsStartingFromDate, interestChargedFromDate, inArrearsTolerance);
} }
} }
@@ -57,6 +57,7 @@ import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository; import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy; import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException; import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
import org.mifosplatform.portfolio.loanproduct.serialization.LoanProductCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.note.domain.Note; import org.mifosplatform.portfolio.note.domain.Note;
import org.mifosplatform.portfolio.note.domain.NoteRepository; import org.mifosplatform.portfolio.note.domain.NoteRepository;
import org.mifosplatform.useradministration.domain.AppUser; import org.mifosplatform.useradministration.domain.AppUser;
@@ -92,19 +93,21 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory; private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
private final CalendarRepository calendarRepository; private final CalendarRepository calendarRepository;
private final CalendarInstanceRepository calendarInstanceRepository; private final CalendarInstanceRepository calendarInstanceRepository;
private final LoanProductCommandFromApiJsonDeserializer loanProductCommandFromApiJsonDeserializer;
@Autowired @Autowired
public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper, public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper,
final LoanApplicationTransitionApiJsonValidator loanApplicationTransitionApiJsonValidator, final LoanApplicationTransitionApiJsonValidator loanApplicationTransitionApiJsonValidator,
final LoanApplicationCommandFromApiJsonHelper fromApiJsonDeserializer, final AprCalculator aprCalculator, final LoanApplicationCommandFromApiJsonHelper fromApiJsonDeserializer, final AprCalculator aprCalculator,
final LoanAssembler loanAssembler, final LoanChargeAssembler loanChargeAssembler, final LoanAssembler loanAssembler, final LoanChargeAssembler loanChargeAssembler,
final CollateralAssembler loanCollateralAssembler, final LoanRepository loanRepository, final CollateralAssembler loanCollateralAssembler, final LoanRepository loanRepository, final NoteRepository noteRepository,
final NoteRepository noteRepository, final LoanScheduleCalculationPlatformService calculationPlatformService, final LoanScheduleCalculationPlatformService calculationPlatformService, final ClientRepository clientRepository,
final ClientRepository clientRepository, final LoanProductRepository loanProductRepository, final LoanProductRepository loanProductRepository, final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory,
final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, final LoanSummaryWrapper loanSummaryWrapper, final LoanSummaryWrapper loanSummaryWrapper,
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory, final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
final CalendarRepository calendarRepository, final CalendarInstanceRepository calendarInstanceRepository) { final CalendarRepository calendarRepository, final CalendarInstanceRepository calendarInstanceRepository,
this.context = context; final LoanProductCommandFromApiJsonDeserializer loanProductCommandFromApiJsonDeserializer) {
this.context = context;
this.fromJsonHelper = fromJsonHelper; this.fromJsonHelper = fromJsonHelper;
this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator; this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator;
this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.fromApiJsonDeserializer = fromApiJsonDeserializer;
@@ -122,6 +125,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory; this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
this.calendarRepository = calendarRepository; this.calendarRepository = calendarRepository;
this.calendarInstanceRepository = calendarInstanceRepository; this.calendarInstanceRepository = calendarInstanceRepository;
this.loanProductCommandFromApiJsonDeserializer = loanProductCommandFromApiJsonDeserializer;
} }
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() { private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
@@ -199,6 +203,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
} }
final Loan existingLoanApplication = retrieveLoanBy(loanId); final Loan existingLoanApplication = retrieveLoanBy(loanId);
this.loanProductCommandFromApiJsonDeserializer.validateMinMaxConstraints(command.parsedJson(), existingLoanApplication.repaymentScheduleDetail(), "loan");
if (!existingLoanApplication.isSubmittedAndPendingApproval()) { throw new LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified( if (!existingLoanApplication.isSubmittedAndPendingApproval()) { throw new LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified(
loanId); } loanId); }
@@ -42,11 +42,11 @@ import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionProcessingS
import org.mifosplatform.portfolio.loanaccount.exception.LoanTransactionProcessingStrategyNotFoundException; import org.mifosplatform.portfolio.loanaccount.exception.LoanTransactionProcessingStrategyNotFoundException;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanSchedule; import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanSchedule;
import org.mifosplatform.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler; import org.mifosplatform.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler;
import org.mifosplatform.portfolio.loanaccount.serialization.LoanApplicationCommandFromApiJsonHelper;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct; import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository; import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy; import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException; import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
import org.mifosplatform.portfolio.loanproduct.serialization.LoanProductCommandFromApiJsonDeserializer;
import org.mifosplatform.useradministration.domain.AppUser; import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -69,7 +69,7 @@ public class LoanAssembler {
private final FromJsonHelper fromApiJsonHelper; private final FromJsonHelper fromApiJsonHelper;
private final LoanSummaryWrapper loanSummaryWrapper; private final LoanSummaryWrapper loanSummaryWrapper;
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory; private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
private final LoanApplicationCommandFromApiJsonHelper fromApiJsonDeserializer; private final LoanProductCommandFromApiJsonDeserializer loanProductCommandFromApiJsonDeserializer;
@Autowired @Autowired
public LoanAssembler(final FromJsonHelper fromApiJsonHelper, final LoanProductRepository loanProductRepository, public LoanAssembler(final FromJsonHelper fromApiJsonHelper, final LoanProductRepository loanProductRepository,
@@ -79,7 +79,7 @@ public class LoanAssembler {
final LoanScheduleAssembler loanScheduleAssembler, final LoanChargeAssembler loanChargeAssembler, final LoanScheduleAssembler loanScheduleAssembler, final LoanChargeAssembler loanChargeAssembler,
final CollateralAssembler loanCollateralAssembler, final LoanSummaryWrapper loanSummaryWrapper, final CollateralAssembler loanCollateralAssembler, final LoanSummaryWrapper loanSummaryWrapper,
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory, final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
final LoanApplicationCommandFromApiJsonHelper fromApiJsonDeserializer) { final LoanProductCommandFromApiJsonDeserializer loanProductCommandFromApiJsonDeserializer) {
this.fromApiJsonHelper = fromApiJsonHelper; this.fromApiJsonHelper = fromApiJsonHelper;
this.loanProductRepository = loanProductRepository; this.loanProductRepository = loanProductRepository;
this.clientRepository = clientRepository; this.clientRepository = clientRepository;
@@ -93,7 +93,7 @@ public class LoanAssembler {
this.loanCollateralAssembler = loanCollateralAssembler; this.loanCollateralAssembler = loanCollateralAssembler;
this.loanSummaryWrapper = loanSummaryWrapper; this.loanSummaryWrapper = loanSummaryWrapper;
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory; this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.loanProductCommandFromApiJsonDeserializer = loanProductCommandFromApiJsonDeserializer;
} }
public Loan assembleFrom(final JsonCommand command, final AppUser currentUser) { public Loan assembleFrom(final JsonCommand command, final AppUser currentUser) {
@@ -118,7 +118,7 @@ public class LoanAssembler {
if (loanProduct == null) { throw new LoanProductNotFoundException(productId); } if (loanProduct == null) { throw new LoanProductNotFoundException(productId); }
//validate min and max constraint parameters //validate min and max constraint parameters
this.fromApiJsonDeserializer.validateMinMaxConstraintValues(element, loanProduct); this.loanProductCommandFromApiJsonDeserializer.validateMinMaxConstraints(element, loanProduct.loanProductRelatedDetail(), "loan");
final Fund fund = findFundByIdIfProvided(fundId); final Fund fund = findFundByIdIfProvided(fundId);
final Staff loanOfficer = findLoanOfficerByIdIfProvided(loanOfficerId); final Staff loanOfficer = findLoanOfficerByIdIfProvided(loanOfficerId);
@@ -57,11 +57,12 @@ import org.springframework.stereotype.Component;
public class LoanProductsApiResource { public class LoanProductsApiResource {
private final Set<String> LOAN_PRODUCT_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "name", "description", "fundId", private final Set<String> LOAN_PRODUCT_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "name", "description", "fundId",
"fundName", "currency", "principal", "numberOfRepayments", "repaymentEvery", "repaymentFrequencyType", "interestRatePerPeriod", "fundName", "currency", "principal", "minPrincipal", "maxPrincipal", "numberOfRepayments", "minNumberOfRepayments",
"interestRateFrequencyType", "annualInterestRate", "amortizationType", "interestType", "interestCalculationPeriodType", "maxNumberOfRepayments", "repaymentEvery", "repaymentFrequencyType", "interestRatePerPeriod", "minInterestRatePerPeriod",
"inArrearsTolerance", "transactionProcessingStrategyId", "transactionProcessingStrategyName", "charges", "accountingRule", "maxInterestRatePerPeriod", "interestRateFrequencyType", "annualInterestRate", "amortizationType", "interestType",
"accountingMappings", "fundOptions", "currencyOptions", "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "interestCalculationPeriodType", "inArrearsTolerance", "transactionProcessingStrategyId", "transactionProcessingStrategyName",
"amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", "charges", "accountingRule", "accountingMappings", "fundOptions", "currencyOptions", "repaymentFrequencyTypeOptions",
"interestRateFrequencyTypeOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions",
"transactionProcessingStrategyOptions", "chargeOptions", "accountingOptions", "accountingRuleOptions", "transactionProcessingStrategyOptions", "chargeOptions", "accountingOptions", "accountingRuleOptions",
"accountingMappingOptions")); "accountingMappingOptions"));
@@ -40,9 +40,13 @@ public class LoanProductData {
private BigDecimal minPrincipal; private BigDecimal minPrincipal;
private BigDecimal maxPrincipal; private BigDecimal maxPrincipal;
private final Integer numberOfRepayments; private final Integer numberOfRepayments;
private final Integer minNumberOfRepayments;
private final Integer maxNumberOfRepayments;
private final Integer repaymentEvery; private final Integer repaymentEvery;
private final EnumOptionData repaymentFrequencyType; private final EnumOptionData repaymentFrequencyType;
private final BigDecimal interestRatePerPeriod; private final BigDecimal interestRatePerPeriod;
private final BigDecimal minInterestRatePerPeriod;
private final BigDecimal maxInterestRatePerPeriod;
private final EnumOptionData interestRateFrequencyType; private final EnumOptionData interestRateFrequencyType;
private final BigDecimal annualInterestRate; private final BigDecimal annualInterestRate;
@@ -86,8 +90,12 @@ public class LoanProductData {
final BigDecimal maxPrincipal = null; final BigDecimal maxPrincipal = null;
final BigDecimal tolerance = null; final BigDecimal tolerance = null;
final Integer numberOfRepayments = null; final Integer numberOfRepayments = null;
final Integer minNumberOfRepayments = null;
final Integer maxNumberOfRepayments = null;
final Integer repaymentEvery = null; final Integer repaymentEvery = null;
final BigDecimal interestRatePerPeriod = null; final BigDecimal interestRatePerPeriod = null;
final BigDecimal minInterestRatePerPeriod = null;
final BigDecimal maxInterestRatePerPeriod = null;
final BigDecimal annualInterestRate = null; final BigDecimal annualInterestRate = null;
final EnumOptionData repaymentFrequencyType = null; final EnumOptionData repaymentFrequencyType = null;
final EnumOptionData interestRateFrequencyType = null; final EnumOptionData interestRateFrequencyType = null;
@@ -101,8 +109,8 @@ public class LoanProductData {
final Collection<ChargeData> charges = null; final Collection<ChargeData> charges = null;
final EnumOptionData accountingType = null; final EnumOptionData accountingType = null;
return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, repaymentEvery, return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery,
interestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType,
interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId, interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId,
transactionProcessingStrategyName, charges, accountingType); transactionProcessingStrategyName, charges, accountingType);
} }
@@ -114,8 +122,12 @@ public class LoanProductData {
final BigDecimal maxPrincipal = null; final BigDecimal maxPrincipal = null;
final BigDecimal tolerance = null; final BigDecimal tolerance = null;
final Integer numberOfRepayments = null; final Integer numberOfRepayments = null;
final Integer minNumberOfRepayments = null;
final Integer maxNumberOfRepayments = null;
final Integer repaymentEvery = null; final Integer repaymentEvery = null;
final BigDecimal interestRatePerPeriod = null; final BigDecimal interestRatePerPeriod = null;
final BigDecimal minInterestRatePerPeriod = null;
final BigDecimal maxInterestRatePerPeriod = null;
final BigDecimal annualInterestRate = null; final BigDecimal annualInterestRate = null;
final EnumOptionData repaymentFrequencyType = null; final EnumOptionData repaymentFrequencyType = null;
final EnumOptionData interestRateFrequencyType = null; final EnumOptionData interestRateFrequencyType = null;
@@ -129,8 +141,8 @@ public class LoanProductData {
final Collection<ChargeData> charges = null; final Collection<ChargeData> charges = null;
final EnumOptionData accountingType = null; final EnumOptionData accountingType = null;
return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, repaymentEvery, return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery,
interestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType,
interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId, interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId,
transactionProcessingStrategyName, charges, accountingType); transactionProcessingStrategyName, charges, accountingType);
} }
@@ -145,8 +157,12 @@ public class LoanProductData {
final BigDecimal maxPrincipal = null; final BigDecimal maxPrincipal = null;
final BigDecimal tolerance = null; final BigDecimal tolerance = null;
final Integer numberOfRepayments = null; final Integer numberOfRepayments = null;
final Integer minNumberOfRepayments = null;
final Integer maxNumberOfRepayments = null;
final Integer repaymentEvery = null; final Integer repaymentEvery = null;
final BigDecimal interestRatePerPeriod = null; final BigDecimal interestRatePerPeriod = null;
final BigDecimal minInterestRatePerPeriod = null;
final BigDecimal maxInterestRatePerPeriod = null;
final BigDecimal annualInterestRate = null; final BigDecimal annualInterestRate = null;
final EnumOptionData repaymentFrequencyType = LoanEnumerations.repaymentFrequencyType(PeriodFrequencyType.MONTHS); final EnumOptionData repaymentFrequencyType = LoanEnumerations.repaymentFrequencyType(PeriodFrequencyType.MONTHS);
final EnumOptionData interestRateFrequencyType = LoanEnumerations.interestRateFrequencyType(PeriodFrequencyType.MONTHS); final EnumOptionData interestRateFrequencyType = LoanEnumerations.interestRateFrequencyType(PeriodFrequencyType.MONTHS);
@@ -161,8 +177,9 @@ public class LoanProductData {
final Collection<ChargeData> charges = null; final Collection<ChargeData> charges = null;
final EnumOptionData accountingType = LoanEnumerations.accountingRuleType(AccountingRuleType.NONE); final EnumOptionData accountingType = LoanEnumerations.accountingRuleType(AccountingRuleType.NONE);
return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, repaymentEvery, return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments,
interestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod,
maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType,
interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId, interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId,
transactionProcessingStrategyName, charges, accountingType); transactionProcessingStrategyName, charges, accountingType);
} }
@@ -178,12 +195,14 @@ public class LoanProductData {
public LoanProductData(final Long id, final String name, final String description, final CurrencyData currency, public LoanProductData(final Long id, final String name, final String description, final CurrencyData currency,
final BigDecimal principal, final BigDecimal minPrincipal, final BigDecimal maxPrincipal, final BigDecimal tolerance, final BigDecimal principal, final BigDecimal minPrincipal, final BigDecimal maxPrincipal, final BigDecimal tolerance,
final Integer numberOfRepayments, final Integer repaymentEvery, final BigDecimal interestRatePerPeriod, final Integer numberOfRepayments, final Integer minNumberOfRepayments, final Integer maxNumberOfRepayments,
final BigDecimal annualInterestRate, final EnumOptionData repaymentFrequencyType, final Integer repaymentEvery, final BigDecimal interestRatePerPeriod, final BigDecimal minInterestRatePerPeriod,
final BigDecimal maxInterestRatePerPeriod, final BigDecimal annualInterestRate, final EnumOptionData repaymentFrequencyType,
final EnumOptionData interestRateFrequencyType, final EnumOptionData amortizationType, final EnumOptionData interestType, final EnumOptionData interestRateFrequencyType, final EnumOptionData amortizationType, final EnumOptionData interestType,
final EnumOptionData interestCalculationPeriodType, final Long fundId, final String fundName, final EnumOptionData interestCalculationPeriodType, final Long fundId, final String fundName,
final Long transactionProcessingStrategyId, final String transactionProcessingStrategyName, final Long transactionProcessingStrategyId, final String transactionProcessingStrategyName,
final Collection<ChargeData> charges, final EnumOptionData accountingType) { final Collection<ChargeData> charges, final EnumOptionData accountingType) {
this.id = id; this.id = id;
this.name = name; this.name = name;
this.description = description; this.description = description;
@@ -193,8 +212,12 @@ public class LoanProductData {
this.maxPrincipal = maxPrincipal; this.maxPrincipal = maxPrincipal;
this.inArrearsTolerance = tolerance; this.inArrearsTolerance = tolerance;
this.numberOfRepayments = numberOfRepayments; this.numberOfRepayments = numberOfRepayments;
this.minNumberOfRepayments = minNumberOfRepayments;
this.maxNumberOfRepayments = maxNumberOfRepayments;
this.repaymentEvery = repaymentEvery; this.repaymentEvery = repaymentEvery;
this.interestRatePerPeriod = interestRatePerPeriod; this.interestRatePerPeriod = interestRatePerPeriod;
this.minInterestRatePerPeriod = minInterestRatePerPeriod;
this.maxInterestRatePerPeriod = maxInterestRatePerPeriod;
this.annualInterestRate = annualInterestRate; this.annualInterestRate = annualInterestRate;
this.repaymentFrequencyType = repaymentFrequencyType; this.repaymentFrequencyType = repaymentFrequencyType;
this.interestRateFrequencyType = interestRateFrequencyType; this.interestRateFrequencyType = interestRateFrequencyType;
@@ -227,8 +250,7 @@ public class LoanProductData {
final Collection<CurrencyData> currencyOptions, final List<EnumOptionData> amortizationTypeOptions, final Collection<CurrencyData> currencyOptions, final List<EnumOptionData> amortizationTypeOptions,
final List<EnumOptionData> interestTypeOptions, final List<EnumOptionData> interestCalculationPeriodTypeOptions, final List<EnumOptionData> interestTypeOptions, final List<EnumOptionData> interestCalculationPeriodTypeOptions,
final List<EnumOptionData> repaymentFrequencyTypeOptions, final List<EnumOptionData> interestRateFrequencyTypeOptions, final List<EnumOptionData> repaymentFrequencyTypeOptions, final List<EnumOptionData> interestRateFrequencyTypeOptions,
final Collection<FundData> fundOptions, final Collection<FundData> fundOptions, final Collection<TransactionProcessingStrategyData> transactionStrategyOptions,
final Collection<TransactionProcessingStrategyData> transactionStrategyOptions,
final Map<String, List<GLAccountData>> accountingMappingOptions, final List<EnumOptionData> accountingRuleOptions, final Map<String, List<GLAccountData>> accountingMappingOptions, final List<EnumOptionData> accountingRuleOptions,
final Map<String, Object> accountingMappings) { final Map<String, Object> accountingMappings) {
this.id = productData.id; this.id = productData.id;
@@ -242,8 +264,12 @@ public class LoanProductData {
this.maxPrincipal = productData.maxPrincipal; this.maxPrincipal = productData.maxPrincipal;
this.inArrearsTolerance = productData.inArrearsTolerance; this.inArrearsTolerance = productData.inArrearsTolerance;
this.numberOfRepayments = productData.numberOfRepayments; this.numberOfRepayments = productData.numberOfRepayments;
this.minNumberOfRepayments = productData.minNumberOfRepayments;
this.maxNumberOfRepayments = productData.maxNumberOfRepayments;
this.repaymentEvery = productData.repaymentEvery; this.repaymentEvery = productData.repaymentEvery;
this.interestRatePerPeriod = productData.interestRatePerPeriod; this.interestRatePerPeriod = productData.interestRatePerPeriod;
this.minInterestRatePerPeriod = productData.minInterestRatePerPeriod;
this.maxInterestRatePerPeriod = productData.maxInterestRatePerPeriod;
this.annualInterestRate = productData.annualInterestRate; this.annualInterestRate = productData.annualInterestRate;
this.repaymentFrequencyType = productData.repaymentFrequencyType; this.repaymentFrequencyType = productData.repaymentFrequencyType;
this.interestRateFrequencyType = productData.interestRateFrequencyType; this.interestRateFrequencyType = productData.interestRateFrequencyType;
@@ -91,16 +91,20 @@ public class LoanProduct extends AbstractPersistable<Long> {
final PeriodFrequencyType interestFrequencyType = PeriodFrequencyType.fromInt(command final PeriodFrequencyType interestFrequencyType = PeriodFrequencyType.fromInt(command
.integerValueOfParameterNamed("interestRateFrequencyType")); .integerValueOfParameterNamed("interestRateFrequencyType"));
final BigDecimal interestRatePerPeriod = command.bigDecimalValueOfParameterNamed("interestRatePerPeriod"); final BigDecimal interestRatePerPeriod = command.bigDecimalValueOfParameterNamed("interestRatePerPeriod");
final BigDecimal minInterestRatePerPeriod = command.bigDecimalValueOfParameterNamed("minInterestRatePerPeriod");
final BigDecimal maxInterestRatePerPeriod = command.bigDecimalValueOfParameterNamed("maxInterestRatePerPeriod");
final BigDecimal annualInterestRate = aprCalculator.calculateFrom(interestFrequencyType, interestRatePerPeriod); final BigDecimal annualInterestRate = aprCalculator.calculateFrom(interestFrequencyType, interestRatePerPeriod);
final Integer repaymentEvery = command.integerValueOfParameterNamed("repaymentEvery"); final Integer repaymentEvery = command.integerValueOfParameterNamed("repaymentEvery");
final Integer numberOfRepayments = command.integerValueOfParameterNamed("numberOfRepayments"); final Integer numberOfRepayments = command.integerValueOfParameterNamed("numberOfRepayments");
final Integer minNumberOfRepayments = command.integerValueOfParameterNamed("minNumberOfRepayments");
final Integer maxNumberOfRepayments = command.integerValueOfParameterNamed("maxNumberOfRepayments");
final BigDecimal inArrearsTolerance = command.bigDecimalValueOfParameterNamed("inArrearsTolerance"); final BigDecimal inArrearsTolerance = command.bigDecimalValueOfParameterNamed("inArrearsTolerance");
final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(command.integerValueOfParameterNamed("accountingRule")); final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(command.integerValueOfParameterNamed("accountingRule"));
return new LoanProduct(fund, loanTransactionProcessingStrategy, name, description, currency, principal, minPrincipal, maxPrincipal, return new LoanProduct(fund, loanTransactionProcessingStrategy, name, description, currency, principal, minPrincipal, maxPrincipal,
interestRatePerPeriod, interestFrequencyType, annualInterestRate, interestMethod, interestCalculationPeriodMethod, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType, annualInterestRate, interestMethod, interestCalculationPeriodMethod,
repaymentEvery, repaymentFrequencyType, numberOfRepayments, amortizationMethod, inArrearsTolerance, productCharges, repaymentEvery, repaymentFrequencyType, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, amortizationMethod, inArrearsTolerance, productCharges,
accountingRuleType); accountingRuleType);
} }
@@ -111,10 +115,12 @@ public class LoanProduct extends AbstractPersistable<Long> {
public LoanProduct(final Fund fund, final LoanTransactionProcessingStrategy transactionProcessingStrategy, final String name, public LoanProduct(final Fund fund, final LoanTransactionProcessingStrategy transactionProcessingStrategy, final String name,
final String description, final MonetaryCurrency currency, final BigDecimal defaultPrincipal, final String description, final MonetaryCurrency currency, final BigDecimal defaultPrincipal,
final BigDecimal defaultMinPrincipal, final BigDecimal defaultMaxPrincipal, final BigDecimal defaultMinPrincipal, final BigDecimal defaultMaxPrincipal,
final BigDecimal defaultNominalInterestRatePerPeriod, final PeriodFrequencyType interestPeriodFrequencyType, final BigDecimal defaultNominalInterestRatePerPeriod, final BigDecimal defaultMinNominalInterestRatePerPeriod,
final BigDecimal defaultMaxNominalInterestRatePerPeriod, final PeriodFrequencyType interestPeriodFrequencyType,
final BigDecimal defaultAnnualNominalInterestRate, final InterestMethod interestMethod, final BigDecimal defaultAnnualNominalInterestRate, final InterestMethod interestMethod,
final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Integer repayEvery, final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Integer repayEvery,
final PeriodFrequencyType repaymentFrequencyType, final Integer defaultNumberOfInstallments, final PeriodFrequencyType repaymentFrequencyType, final Integer defaultNumberOfInstallments,
final Integer defaultMinNumberOfInstallments, final Integer defaultMaxNumberOfInstallments,
final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance, final List<Charge> charges, final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance, final List<Charge> charges,
final AccountingRuleType accountingRuleType) { final AccountingRuleType accountingRuleType) {
this.fund = fund; this.fund = fund;
@@ -131,9 +137,10 @@ public class LoanProduct extends AbstractPersistable<Long> {
} }
this.loanProductRelatedDetail = new LoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal, this.loanProductRelatedDetail = new LoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal,
defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, defaultNominalInterestRatePerPeriod, defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod,
interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType, defaultNumberOfInstallments, amortizationMethod, interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery,
inArrearsTolerance); repaymentFrequencyType, defaultNumberOfInstallments, defaultMinNumberOfInstallments, defaultMaxNumberOfInstallments,
amortizationMethod, inArrearsTolerance);
if (accountingRuleType != null) { if (accountingRuleType != null) {
this.accountingRule = accountingRuleType.getValue(); this.accountingRule = accountingRuleType.getValue();
@@ -234,6 +241,10 @@ public class LoanProduct extends AbstractPersistable<Long> {
return AccountingRuleType.ACCRUAL_BASED.getValue().equals(this.accountingRule); return AccountingRuleType.ACCRUAL_BASED.getValue().equals(this.accountingRule);
} }
public Money getPrincipalAmount(){
return this.loanProductRelatedDetail.getPrincipal();
}
public Money getMinPrincipalAmount(){ public Money getMinPrincipalAmount(){
return this.loanProductRelatedDetail.getMinPrincipal(); return this.loanProductRelatedDetail.getMinPrincipal();
} }
@@ -241,4 +252,32 @@ public class LoanProduct extends AbstractPersistable<Long> {
public Money getMaxPrincipalAmount(){ public Money getMaxPrincipalAmount(){
return this.loanProductRelatedDetail.getMaxPrincipal(); return this.loanProductRelatedDetail.getMaxPrincipal();
} }
public BigDecimal getNominalInterestRatePerPeriod() {
return this.loanProductRelatedDetail.getNominalInterestRatePerPeriod();
}
public BigDecimal getMinNominalInterestRatePerPeriod() {
return this.loanProductRelatedDetail.getMinNominalInterestRatePerPeriod();
}
public BigDecimal getMaxNominalInterestRatePerPeriod(){
return this.loanProductRelatedDetail.getMaxNominalInterestRatePerPeriod();
}
public Integer getNumberOfRepayments(){
return this.loanProductRelatedDetail.getNumberOfRepayments();
}
public Integer getMinNumberOfRepayments() {
return this.loanProductRelatedDetail.getMinNumberOfRepayments();
}
public Integer getMaxNumberOfRepayments() {
return this.loanProductRelatedDetail.getMaxNumberOfRepayments();
}
public LoanProductRelatedDetail loanProductRelatedDetail(){
return this.loanProductRelatedDetail;
}
} }
@@ -20,7 +20,6 @@ import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money; import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.portfolio.loanaccount.domain.Loan; import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator; import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator;
import org.mifosplatform.portfolio.loanproduct.exception.NotInMinMaxRangeException;
/** /**
* LoanRepaymentScheduleDetail encapsulates all the details of a * LoanRepaymentScheduleDetail encapsulates all the details of a
@@ -35,15 +34,21 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
@Column(name = "principal_amount", scale = 6, precision = 19, nullable = false) @Column(name = "principal_amount", scale = 6, precision = 19, nullable = false)
private BigDecimal principal; private BigDecimal principal;
@Column(name = "min_principal_amount", scale = 6, precision = 19, nullable = false) @Column(name = "min_principal_amount", scale = 6, precision = 19, nullable = true)
private BigDecimal minPrincipal; private BigDecimal minPrincipal;
@Column(name = "max_principal_amount", scale = 6, precision = 19, nullable = false) @Column(name = "max_principal_amount", scale = 6, precision = 19, nullable = true)
private BigDecimal maxPrincipal; private BigDecimal maxPrincipal;
@Column(name = "nominal_interest_rate_per_period", scale = 6, precision = 19, nullable = false) @Column(name = "nominal_interest_rate_per_period", scale = 6, precision = 19, nullable = false)
private BigDecimal nominalInterestRatePerPeriod; private BigDecimal nominalInterestRatePerPeriod;
@Column(name = "min_nominal_interest_rate_per_period", scale = 6, precision = 19, nullable = true)
private BigDecimal minNominalInterestRatePerPeriod;
@Column(name = "max_nominal_interest_rate_per_period", scale = 6, precision = 19, nullable = true)
private BigDecimal maxNominalInterestRatePerPeriod;
// FIXME - move away form JPA ordinal use for enums using just integer - // FIXME - move away form JPA ordinal use for enums using just integer -
// requires sql patch for existing users of software. // requires sql patch for existing users of software.
@Enumerated(EnumType.ORDINAL) @Enumerated(EnumType.ORDINAL)
@@ -77,6 +82,12 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
@Column(name = "number_of_repayments", nullable = false) @Column(name = "number_of_repayments", nullable = false)
private Integer numberOfRepayments; private Integer numberOfRepayments;
@Column(name = "min_number_of_repayments", nullable = true)
private Integer minNumberOfRepayments;
@Column(name = "max_number_of_repayments", nullable = true)
private Integer maxNumberOfRepayments;
// FIXME - move away form JPA ordinal use for enums using just integer - // FIXME - move away form JPA ordinal use for enums using just integer -
// requires sql patch for existing users of software. // requires sql patch for existing users of software.
@Enumerated(EnumType.ORDINAL) @Enumerated(EnumType.ORDINAL)
@@ -88,14 +99,17 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
public static LoanProductRelatedDetail createFrom(final MonetaryCurrency currency, final BigDecimal principal, public static LoanProductRelatedDetail createFrom(final MonetaryCurrency currency, final BigDecimal principal,
final BigDecimal minPrincipal, final BigDecimal maxPrincipal, final BigDecimal nominalInterestRatePerPeriod, final BigDecimal minPrincipal, final BigDecimal maxPrincipal, final BigDecimal nominalInterestRatePerPeriod,
final BigDecimal minNominalInterestRatePerPeriod, final BigDecimal maxNominalInterestRatePerPeriod,
final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal nominalAnnualInterestRate, final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal nominalAnnualInterestRate,
final InterestMethod interestMethod, final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final InterestMethod interestMethod, final InterestCalculationPeriodMethod interestCalculationPeriodMethod,
final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType, final Integer numberOfRepayments,
final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance) { final Integer minNumberOfRepayments, final Integer maxNumberOfRepayments, final AmortizationMethod amortizationMethod,
final BigDecimal inArrearsTolerance) {
return new LoanProductRelatedDetail(currency, principal, minPrincipal, maxPrincipal, nominalInterestRatePerPeriod, interestRatePeriodFrequencyType, return new LoanProductRelatedDetail(currency, principal, minPrincipal, maxPrincipal, nominalInterestRatePerPeriod,
minNominalInterestRatePerPeriod, maxNominalInterestRatePerPeriod, interestRatePeriodFrequencyType,
nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentPeriodFrequencyType, nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentPeriodFrequencyType,
numberOfRepayments, amortizationMethod, inArrearsTolerance); numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, amortizationMethod, inArrearsTolerance);
} }
protected LoanProductRelatedDetail() { protected LoanProductRelatedDetail() {
@@ -104,16 +118,20 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
public LoanProductRelatedDetail(final MonetaryCurrency currency, final BigDecimal defaultPrincipal, public LoanProductRelatedDetail(final MonetaryCurrency currency, final BigDecimal defaultPrincipal,
final BigDecimal defaultMinPrincipal, final BigDecimal defaultMaxPrincipal, final BigDecimal defaultMinPrincipal, final BigDecimal defaultMaxPrincipal,
final BigDecimal defaultNominalInterestRatePerPeriod, final PeriodFrequencyType interestPeriodFrequencyType, final BigDecimal defaultNominalInterestRatePerPeriod, final BigDecimal defaultMinNominalInterestRatePerPeriod,
final BigDecimal defaultMaxNominalInterestRatePerPeriod, final PeriodFrequencyType interestPeriodFrequencyType,
final BigDecimal defaultAnnualNominalInterestRate, final InterestMethod interestMethod, final BigDecimal defaultAnnualNominalInterestRate, final InterestMethod interestMethod,
final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Integer repayEvery, final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Integer repayEvery,
final PeriodFrequencyType repaymentFrequencyType, final Integer defaultNumberOfRepayments, final PeriodFrequencyType repaymentFrequencyType, final Integer defaultNumberOfRepayments,
final Integer defaultMinNumberOfRepayments, final Integer defaultMaxNumberOfRepayments,
final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance) { final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance) {
this.currency = currency; this.currency = currency;
this.principal = defaultPrincipal; this.principal = defaultPrincipal;
this.minPrincipal = defaultMinPrincipal; this.minPrincipal = defaultMinPrincipal;
this.maxPrincipal = defaultMaxPrincipal; this.maxPrincipal = defaultMaxPrincipal;
this.nominalInterestRatePerPeriod = defaultNominalInterestRatePerPeriod; this.nominalInterestRatePerPeriod = defaultNominalInterestRatePerPeriod;
this.minNominalInterestRatePerPeriod = defaultMinNominalInterestRatePerPeriod;
this.maxNominalInterestRatePerPeriod = defaultMaxNominalInterestRatePerPeriod;
this.interestPeriodFrequencyType = interestPeriodFrequencyType; this.interestPeriodFrequencyType = interestPeriodFrequencyType;
this.annualNominalInterestRate = defaultAnnualNominalInterestRate; this.annualNominalInterestRate = defaultAnnualNominalInterestRate;
this.interestMethod = interestMethod; this.interestMethod = interestMethod;
@@ -121,6 +139,8 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
this.repayEvery = repayEvery; this.repayEvery = repayEvery;
this.repaymentPeriodFrequencyType = repaymentFrequencyType; this.repaymentPeriodFrequencyType = repaymentFrequencyType;
this.numberOfRepayments = defaultNumberOfRepayments; this.numberOfRepayments = defaultNumberOfRepayments;
this.minNumberOfRepayments = defaultMinNumberOfRepayments;
this.maxNumberOfRepayments = defaultMaxNumberOfRepayments;
this.amortizationMethod = amortizationMethod; this.amortizationMethod = amortizationMethod;
if (inArrearsTolerance != null && BigDecimal.ZERO.compareTo(inArrearsTolerance) == 0) { if (inArrearsTolerance != null && BigDecimal.ZERO.compareTo(inArrearsTolerance) == 0) {
this.inArrearsTolerance = null; this.inArrearsTolerance = null;
@@ -153,6 +173,16 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
return BigDecimal.valueOf(Double.valueOf(this.nominalInterestRatePerPeriod.stripTrailingZeros().toString())); return BigDecimal.valueOf(Double.valueOf(this.nominalInterestRatePerPeriod.stripTrailingZeros().toString()));
} }
public BigDecimal getMinNominalInterestRatePerPeriod() {
return this.minNominalInterestRatePerPeriod == null ? null : BigDecimal.valueOf(Double.valueOf(this.minNominalInterestRatePerPeriod
.stripTrailingZeros().toString()));
}
public BigDecimal getMaxNominalInterestRatePerPeriod() {
return this.maxNominalInterestRatePerPeriod == null ? null : BigDecimal.valueOf(Double.valueOf(this.maxNominalInterestRatePerPeriod
.stripTrailingZeros().toString()));
}
public PeriodFrequencyType getInterestPeriodFrequencyType() { public PeriodFrequencyType getInterestPeriodFrequencyType() {
return interestPeriodFrequencyType; return interestPeriodFrequencyType;
} }
@@ -184,6 +214,14 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
return numberOfRepayments; return numberOfRepayments;
} }
public Integer getMinNumberOfRepayments() {
return minNumberOfRepayments;
}
public Integer getMaxNumberOfRepayments() {
return maxNumberOfRepayments;
}
public AmortizationMethod getAmortizationMethod() { public AmortizationMethod getAmortizationMethod() {
return amortizationMethod; return amortizationMethod;
} }
@@ -227,7 +265,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
final String localeAsInput = command.locale(); final String localeAsInput = command.locale();
final String minPrincipalParamName = "minPrincipal"; final String minPrincipalParamName = "minPrincipal";
if (command.isChangeInBigDecimalParameterNamed(minPrincipalParamName, this.minPrincipal)) { if (command.isChangeInBigDecimalParameterNamedWithNullCheck(minPrincipalParamName, this.minPrincipal)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minPrincipalParamName); final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minPrincipalParamName);
actualChanges.put(minPrincipalParamName, newValue); actualChanges.put(minPrincipalParamName, newValue);
actualChanges.put("locale", localeAsInput); actualChanges.put("locale", localeAsInput);
@@ -235,7 +273,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
} }
final String maxPrincipalParamName = "maxPrincipal"; final String maxPrincipalParamName = "maxPrincipal";
if (command.isChangeInBigDecimalParameterNamed(maxPrincipalParamName, this.maxPrincipal)) { if (command.isChangeInBigDecimalParameterNamedWithNullCheck(maxPrincipalParamName, this.maxPrincipal)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(maxPrincipalParamName); final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(maxPrincipalParamName);
actualChanges.put(maxPrincipalParamName, newValue); actualChanges.put(maxPrincipalParamName, newValue);
actualChanges.put("locale", localeAsInput); actualChanges.put("locale", localeAsInput);
@@ -248,7 +286,6 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
actualChanges.put(principalParamName, newValue); actualChanges.put(principalParamName, newValue);
actualChanges.put("locale", localeAsInput); actualChanges.put("locale", localeAsInput);
this.principal = newValue; this.principal = newValue;
validatePrincipalAmount();
} }
final String repaymentEveryParamName = "repaymentEvery"; final String repaymentEveryParamName = "repaymentEvery";
@@ -267,6 +304,22 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
this.repaymentPeriodFrequencyType = PeriodFrequencyType.fromInt(newValue); this.repaymentPeriodFrequencyType = PeriodFrequencyType.fromInt(newValue);
} }
final String minNumberOfRepaymentsParamName = "minNumberOfRepayments";
if (command.isChangeInIntegerParameterNamed(minNumberOfRepaymentsParamName, this.minNumberOfRepayments)) {
final Integer newValue = command.integerValueOfParameterNamed(minNumberOfRepaymentsParamName);
actualChanges.put(minNumberOfRepaymentsParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.minNumberOfRepayments = newValue;
}
final String maxNumberOfRepaymentsParamName = "maxNumberOfRepayments";
if (command.isChangeInIntegerParameterNamed(maxNumberOfRepaymentsParamName, this.maxNumberOfRepayments)) {
final Integer newValue = command.integerValueOfParameterNamed(maxNumberOfRepaymentsParamName);
actualChanges.put(maxNumberOfRepaymentsParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.maxNumberOfRepayments = newValue;
}
final String numberOfRepaymentsParamName = "numberOfRepayments"; final String numberOfRepaymentsParamName = "numberOfRepayments";
if (command.isChangeInIntegerParameterNamed(numberOfRepaymentsParamName, this.numberOfRepayments)) { if (command.isChangeInIntegerParameterNamed(numberOfRepaymentsParamName, this.numberOfRepayments)) {
final Integer newValue = command.integerValueOfParameterNamed(numberOfRepaymentsParamName); final Integer newValue = command.integerValueOfParameterNamed(numberOfRepaymentsParamName);
@@ -291,6 +344,22 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
this.inArrearsTolerance = newValue; this.inArrearsTolerance = newValue;
} }
final String minInterestRatePerPeriodParamName = "minInterestRatePerPeriod";
if (command.isChangeInBigDecimalParameterNamedWithNullCheck(minInterestRatePerPeriodParamName, this.minNominalInterestRatePerPeriod)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minInterestRatePerPeriodParamName);
actualChanges.put(minInterestRatePerPeriodParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.minNominalInterestRatePerPeriod = newValue;
}
final String maxInterestRatePerPeriodParamName = "maxInterestRatePerPeriod";
if (command.isChangeInBigDecimalParameterNamedWithNullCheck(maxInterestRatePerPeriodParamName, this.maxNominalInterestRatePerPeriod)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(maxInterestRatePerPeriodParamName);
actualChanges.put(maxInterestRatePerPeriodParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.maxNominalInterestRatePerPeriod = newValue;
}
final String interestRatePerPeriodParamName = "interestRatePerPeriod"; final String interestRatePerPeriodParamName = "interestRatePerPeriod";
if (command.isChangeInBigDecimalParameterNamed(interestRatePerPeriodParamName, this.nominalInterestRatePerPeriod)) { if (command.isChangeInBigDecimalParameterNamed(interestRatePerPeriodParamName, this.nominalInterestRatePerPeriod)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(interestRatePerPeriodParamName); final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(interestRatePerPeriodParamName);
@@ -329,13 +398,6 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
return actualChanges; return actualChanges;
} }
private void validatePrincipalAmount() {
if(this.principal.compareTo(this.minPrincipal) == -1 || this.principal.compareTo(maxPrincipal) == 1){
final String errorMessage = "The Principal amount " + this.principal + " is invalid. Must be an amount between " + this.minPrincipal + " and " + this.maxPrincipal + " inclusive.";
throw new NotInMinMaxRangeException("loan", "principal.amount", errorMessage, this.principal, this.minPrincipal, this.maxPrincipal);
}
}
private void updateInterestRateDerivedFields(final AprCalculator aprCalculator) { private void updateInterestRateDerivedFields(final AprCalculator aprCalculator) {
this.annualNominalInterestRate = aprCalculator.calculateFrom(this.interestPeriodFrequencyType, this.nominalInterestRatePerPeriod); this.annualNominalInterestRate = aprCalculator.calculateFrom(this.interestPeriodFrequencyType, this.nominalInterestRatePerPeriod);
} }
@@ -23,6 +23,7 @@ import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType; import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -36,9 +37,10 @@ public final class LoanProductCommandFromApiJsonDeserializer {
* The parameters supported for this command. * The parameters supported for this command.
*/ */
private final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("locale", "name", "description", "fundId", private final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("locale", "name", "description", "fundId",
"currencyCode", "digitsAfterDecimal", "principal", "minPrincipal", "maxPrincipal", "repaymentEvery", "numberOfRepayments", "repaymentFrequencyType", "currencyCode", "digitsAfterDecimal", "principal", "minPrincipal", "maxPrincipal", "repaymentEvery", "numberOfRepayments",
"interestRatePerPeriod", "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", "minNumberOfRepayments", "maxNumberOfRepayments", "repaymentFrequencyType", "interestRatePerPeriod",
"inArrearsTolerance", "transactionProcessingStrategyId", "charges", "accountingRule", "minInterestRatePerPeriod", "maxInterestRatePerPeriod", "interestRateFrequencyType", "amortizationType", "interestType",
"interestCalculationPeriodType", "inArrearsTolerance", "transactionProcessingStrategyId", "charges", "accountingRule",
LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(),
@@ -81,18 +83,66 @@ public final class LoanProductCommandFromApiJsonDeserializer {
final Integer digitsAfterDecimal = fromApiJsonHelper.extractIntegerNamed("digitsAfterDecimal", element, Locale.getDefault()); final Integer digitsAfterDecimal = fromApiJsonHelper.extractIntegerNamed("digitsAfterDecimal", element, Locale.getDefault());
baseDataValidator.reset().parameter("digitsAfterDecimal").value(digitsAfterDecimal).notNull().inMinMaxRange(0, 6); baseDataValidator.reset().parameter("digitsAfterDecimal").value(digitsAfterDecimal).notNull().inMinMaxRange(0, 6);
final BigDecimal minPrincipal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("minPrincipal", element);
baseDataValidator.reset().parameter("minPrincipal").value(minPrincipal).notNull().positiveAmount();
final BigDecimal maxPrincipal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("maxPrincipal", element);
baseDataValidator.reset().parameter("maxPrincipal").value(maxPrincipal).notNull().positiveAmount();
final BigDecimal principal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element); final BigDecimal principal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element);
baseDataValidator.reset().parameter("principal").value(principal).notNull().positiveAmount().inMinAndMaxAmountRange(minPrincipal, maxPrincipal); baseDataValidator.reset().parameter("principal").value(principal).notNull().positiveAmount();
String minPrincipalParameterName = "minPrincipal";
BigDecimal minPrincipalAmount = null;
if(fromApiJsonHelper.parameterExists(minPrincipalParameterName, element)){
minPrincipalAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minPrincipalParameterName, element);
baseDataValidator.reset().parameter(minPrincipalParameterName).value(minPrincipalAmount).ignoreIfNull().positiveAmount();
}
String maxPrincipalParameterName = "maxPrincipal";
BigDecimal maxPrincipalAmount = null;
if(fromApiJsonHelper.parameterExists(maxPrincipalParameterName, element)){
maxPrincipalAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxPrincipalParameterName, element);
baseDataValidator.reset().parameter(maxPrincipalParameterName).value(maxPrincipalAmount).ignoreIfNull().positiveAmount();
}
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){
baseDataValidator.reset().parameter("principal").value(principal).inMinAndMaxAmountRange(minPrincipalAmount, maxPrincipalAmount);
}
}else{
baseDataValidator.reset().parameter("principal").value(principal).notGreaterThanMax(maxPrincipalAmount);
}
}else if (minPrincipalAmount != null && minPrincipalAmount.compareTo(BigDecimal.ZERO) != -1) {
baseDataValidator.reset().parameter("principal").value(principal).notLessThanMin(minPrincipalAmount);
}
final Integer numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed("numberOfRepayments", element); final Integer numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed("numberOfRepayments", element);
baseDataValidator.reset().parameter("numberOfRepayments").value(numberOfRepayments).notNull().integerGreaterThanZero(); baseDataValidator.reset().parameter("numberOfRepayments").value(numberOfRepayments).notNull().integerGreaterThanZero();
String minNumberOfRepaymentsParameterName = "minNumberOfRepayments";
Integer minNumberOfRepayments = null;
if(fromApiJsonHelper.parameterExists(minNumberOfRepaymentsParameterName, element)){
minNumberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed(minNumberOfRepaymentsParameterName, element);
baseDataValidator.reset().parameter(minNumberOfRepaymentsParameterName).value(minNumberOfRepayments).ignoreIfNull().integerGreaterThanZero();
}
String maxNumberOfRepaymentsParameterName = "maxNumberOfRepayments";
Integer maxNumberOfRepayments = null;
if(fromApiJsonHelper.parameterExists(maxNumberOfRepaymentsParameterName, element)){
maxNumberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed(maxNumberOfRepaymentsParameterName, element);
baseDataValidator.reset().parameter(maxNumberOfRepaymentsParameterName).value(maxNumberOfRepayments).ignoreIfNull().integerGreaterThanZero();
}
if(maxNumberOfRepayments != null && maxNumberOfRepayments.compareTo(0) == 1){
if(minNumberOfRepayments != null && minNumberOfRepayments.compareTo(0) == 1){
baseDataValidator.reset().parameter(maxNumberOfRepaymentsParameterName).value(maxNumberOfRepayments).notLessThanMin(minNumberOfRepayments);
if(minNumberOfRepayments.compareTo(maxNumberOfRepayments) <= 0){
baseDataValidator.reset().parameter("numberOfRepayments").value(numberOfRepayments).inMinMaxRange(minNumberOfRepayments, maxNumberOfRepayments);
}
}else{
baseDataValidator.reset().parameter("numberOfRepayments").value(numberOfRepayments).notGreaterThanMax(maxNumberOfRepayments);
}
}else if(minNumberOfRepayments != null && minNumberOfRepayments.compareTo(0) == 1){
baseDataValidator.reset().parameter("numberOfRepayments").value(numberOfRepayments).notLessThanMin(minNumberOfRepayments);
}
final Integer repaymentEvery = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentEvery", element); final Integer repaymentEvery = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentEvery", element);
baseDataValidator.reset().parameter("repaymentEvery").value(repaymentEvery).notNull().integerGreaterThanZero(); baseDataValidator.reset().parameter("repaymentEvery").value(repaymentEvery).notNull().integerGreaterThanZero();
@@ -103,6 +153,33 @@ public final class LoanProductCommandFromApiJsonDeserializer {
final BigDecimal interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element); final BigDecimal interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element);
baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod).notNull().zeroOrPositiveAmount(); baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod).notNull().zeroOrPositiveAmount();
String minInterestRatePerPeriodParameterName = "minInterestRatePerPeriod";
BigDecimal minInterestRatePerPeriod = null;
if(fromApiJsonHelper.parameterExists(minInterestRatePerPeriodParameterName, element)){
minInterestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minInterestRatePerPeriodParameterName, element);
baseDataValidator.reset().parameter(minInterestRatePerPeriodParameterName).value(minInterestRatePerPeriod).ignoreIfNull().zeroOrPositiveAmount();
}
String maxInterestRatePerPeriodParameterName = "maxInterestRatePerPeriod";
BigDecimal maxInterestRatePerPeriod = null;
if(fromApiJsonHelper.parameterExists(maxInterestRatePerPeriodParameterName, element)){
maxInterestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxInterestRatePerPeriodParameterName, element);
baseDataValidator.reset().parameter(maxInterestRatePerPeriodParameterName).value(maxInterestRatePerPeriod).ignoreIfNull().zeroOrPositiveAmount();
}
if(maxInterestRatePerPeriod != null && maxInterestRatePerPeriod.compareTo(BigDecimal.ZERO) != -1){
if(minInterestRatePerPeriod != null && minInterestRatePerPeriod.compareTo(BigDecimal.ZERO) != -1){
baseDataValidator.reset().parameter(maxInterestRatePerPeriodParameterName).value(maxInterestRatePerPeriod).notLessThanMin(minInterestRatePerPeriod);
if(minInterestRatePerPeriod.compareTo(maxInterestRatePerPeriod) <= 0){
baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod).inMinAndMaxAmountRange(minInterestRatePerPeriod, maxInterestRatePerPeriod);
}
}else{
baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod).notGreaterThanMax(maxInterestRatePerPeriod);
}
}else if(minInterestRatePerPeriod != null && minInterestRatePerPeriod.compareTo(BigDecimal.ZERO) != -1){
baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod).notLessThanMin(minInterestRatePerPeriod);
}
final Integer interestRateFrequencyType = fromApiJsonHelper.extractIntegerNamed("interestRateFrequencyType", element, final Integer interestRateFrequencyType = fromApiJsonHelper.extractIntegerNamed("interestRateFrequencyType", element,
Locale.getDefault()); Locale.getDefault());
baseDataValidator.reset().parameter("interestRateFrequencyType").value(interestRateFrequencyType).notNull().inMinMaxRange(0, 3); baseDataValidator.reset().parameter("interestRateFrequencyType").value(interestRateFrequencyType).notNull().inMinMaxRange(0, 3);
@@ -223,28 +300,19 @@ public final class LoanProductCommandFromApiJsonDeserializer {
BigDecimal minPrincipalAmount = null; BigDecimal minPrincipalAmount = null;
if(fromApiJsonHelper.parameterExists(minPrincipalParameterName, element)){ if(fromApiJsonHelper.parameterExists(minPrincipalParameterName, element)){
minPrincipalAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minPrincipalParameterName, element); minPrincipalAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minPrincipalParameterName, element);
baseDataValidator.reset().parameter(minPrincipalParameterName).value(minPrincipalAmount).ignoreIfNull().positiveAmount();
} }
String maxPrincipalParameterName = "maxPrincipal"; String maxPrincipalParameterName = "maxPrincipal";
BigDecimal maxPrincipalAmount = null; BigDecimal maxPrincipalAmount = null;
if(fromApiJsonHelper.parameterExists(maxPrincipalParameterName, element)){ if(fromApiJsonHelper.parameterExists(maxPrincipalParameterName, element)){
maxPrincipalAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxPrincipalParameterName, element); maxPrincipalAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxPrincipalParameterName, element);
} baseDataValidator.reset().parameter(maxPrincipalParameterName).value(maxPrincipalAmount).ignoreIfNull().positiveAmount();
//Principal amount is allowed to change only when Min and Max principal amounts are sent in JSON request
//Validate if minPrincipal amount or principal amount is part of JSON request.
if(fromApiJsonHelper.parameterExists(minPrincipalParameterName, element) || fromApiJsonHelper.parameterExists("principal", element)){
baseDataValidator.reset().parameter(minPrincipalParameterName).value(minPrincipalAmount).notNull().positiveAmount();
}
//Validate if maxPrincipal amount or principal amount is part of JSON request.
if(fromApiJsonHelper.parameterExists(maxPrincipalParameterName, element) || fromApiJsonHelper.parameterExists("principal", element)){
baseDataValidator.reset().parameter(maxPrincipalParameterName).value(maxPrincipalAmount).notNull().positiveAmount();
} }
if (fromApiJsonHelper.parameterExists("principal", element)) { if (fromApiJsonHelper.parameterExists("principal", element)) {
final BigDecimal principal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element); final BigDecimal principal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element);
baseDataValidator.reset().parameter("principal").value(principal).notNull().positiveAmount().inMinAndMaxAmountRange(minPrincipalAmount, maxPrincipalAmount); baseDataValidator.reset().parameter("principal").value(principal).notNull().positiveAmount();
} }
if (fromApiJsonHelper.parameterExists("inArrearsTolerance", element)) { if (fromApiJsonHelper.parameterExists("inArrearsTolerance", element)) {
@@ -252,9 +320,37 @@ public final class LoanProductCommandFromApiJsonDeserializer {
baseDataValidator.reset().parameter("inArrearsTolerance").value(inArrearsTolerance).ignoreIfNull().zeroOrPositiveAmount(); baseDataValidator.reset().parameter("inArrearsTolerance").value(inArrearsTolerance).ignoreIfNull().zeroOrPositiveAmount();
} }
String minInterestRatePerPeriodParameterName = "minInterestRatePerPeriod";
BigDecimal minInterestRatePerPeriod = null;
if (fromApiJsonHelper.parameterExists(minInterestRatePerPeriodParameterName, element)) {
minInterestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minInterestRatePerPeriodParameterName, element);
baseDataValidator.reset().parameter(minInterestRatePerPeriodParameterName).value(minInterestRatePerPeriod).ignoreIfNull().zeroOrPositiveAmount();
}
String maxInterestRatePerPeriodParameterName = "maxInterestRatePerPeriod";
BigDecimal maxInterestRatePerPeriod = null;
if (fromApiJsonHelper.parameterExists(maxInterestRatePerPeriodParameterName, element)) {
maxInterestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxInterestRatePerPeriodParameterName, element);
baseDataValidator.reset().parameter(maxInterestRatePerPeriodParameterName).value(maxInterestRatePerPeriod).ignoreIfNull().zeroOrPositiveAmount();
}
if (fromApiJsonHelper.parameterExists("interestRatePerPeriod", element)) { if (fromApiJsonHelper.parameterExists("interestRatePerPeriod", element)) {
final BigDecimal interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element); final BigDecimal interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element);
baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod).notNull().zeroOrPositiveAmount(); baseDataValidator.reset().parameter("interestRatePerPeriod").value(interestRatePerPeriod).notNull().positiveAmount();
}
String minNumberOfRepaymentsParameterName = "minNumberOfRepayments";
Integer minNumberOfRepayments = null;
if (fromApiJsonHelper.parameterExists(minNumberOfRepaymentsParameterName, element)) {
minNumberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed(minNumberOfRepaymentsParameterName, element);
baseDataValidator.reset().parameter(minNumberOfRepaymentsParameterName).value(minNumberOfRepayments).ignoreIfNull().integerGreaterThanZero();
}
String maxNumberOfRepaymentsParameterName = "maxNumberOfRepayments";
Integer maxNumberOfRepayments = null;
if (fromApiJsonHelper.parameterExists(maxNumberOfRepaymentsParameterName, element)) {
maxNumberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed(maxNumberOfRepaymentsParameterName, element);
baseDataValidator.reset().parameter(maxNumberOfRepaymentsParameterName).value(maxNumberOfRepayments).ignoreIfNull().integerGreaterThanZero();
} }
if (fromApiJsonHelper.parameterExists("numberOfRepayments", element)) { if (fromApiJsonHelper.parameterExists("numberOfRepayments", element)) {
@@ -352,6 +448,180 @@ public final class LoanProductCommandFromApiJsonDeserializer {
throwExceptionIfValidationWarningsExist(dataValidationErrors); throwExceptionIfValidationWarningsExist(dataValidationErrors);
} }
public void validateMinMaxConstraints(final JsonElement element, final LoanProductRelatedDetail loanProductRelatedDetail, final String resource){
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(resource);
validatePrincipalMinMaxConstraint(element, loanProductRelatedDetail, baseDataValidator);
validateNumberOfRepaymentsMinMaxConstraint(element, loanProductRelatedDetail, baseDataValidator);
validateNominalInterestRatePerPeriodMinMaxConstraint(element, loanProductRelatedDetail, baseDataValidator);
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void validatePrincipalMinMaxConstraint(final JsonElement element, final LoanProductRelatedDetail loanProductRelatedDetail, final DataValidatorBuilder baseDataValidator) {
boolean principalUpdated = false;
boolean minPrincipalUpdated = false;
boolean maxPrincipalUpdated = false;
String principalParameterName = "principal";
BigDecimal principalAmount = null;
if (fromApiJsonHelper.parameterExists(principalParameterName, element)) {
principalAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(principalParameterName, element);
principalUpdated = true;
}else{
principalAmount = loanProductRelatedDetail.getPrincipal().getAmount();
}
String minPrincipalParameterName = "minPrincipal";
BigDecimal minPrincipalAmount = null;
if(fromApiJsonHelper.parameterExists(minPrincipalParameterName, element)){
minPrincipalAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minPrincipalParameterName, element);
minPrincipalUpdated = true;
}else{
minPrincipalAmount = loanProductRelatedDetail.getMinPrincipal().getAmount();
}
String maxPrincipalParameterName = "maxPrincipal";
BigDecimal maxPrincipalAmount = null;
if(fromApiJsonHelper.parameterExists(maxPrincipalParameterName, element)){
maxPrincipalAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxPrincipalParameterName, element);
maxPrincipalUpdated = true;
}else{
maxPrincipalAmount = loanProductRelatedDetail.getMaxPrincipal().getAmount();
}
if(minPrincipalUpdated){
baseDataValidator.reset().parameter(minPrincipalParameterName).value(minPrincipalAmount).notGreaterThanMax(maxPrincipalAmount);
}
if(maxPrincipalUpdated){
baseDataValidator.reset().parameter(maxPrincipalParameterName).value(maxPrincipalAmount).notLessThanMin(minPrincipalAmount);
}
if((principalUpdated || minPrincipalUpdated || maxPrincipalUpdated)){
if((minPrincipalAmount != null && minPrincipalAmount.compareTo(BigDecimal.ZERO) == 1) && (maxPrincipalAmount != null && maxPrincipalAmount.compareTo(BigDecimal.ZERO) == 1)){
baseDataValidator.reset().parameter(principalParameterName).value(principalAmount).inMinAndMaxAmountRange(minPrincipalAmount, maxPrincipalAmount);
}else{
if(minPrincipalAmount != null && minPrincipalAmount.compareTo(BigDecimal.ZERO) == 1){
baseDataValidator.reset().parameter(principalParameterName).value(principalAmount).notLessThanMin(minPrincipalAmount);
}else if(maxPrincipalAmount != null && maxPrincipalAmount.compareTo(BigDecimal.ZERO) == 1){
baseDataValidator.reset().parameter(principalParameterName).value(principalAmount).notGreaterThanMax(maxPrincipalAmount);
}
}
}
}
private void validateNumberOfRepaymentsMinMaxConstraint(final JsonElement element, final LoanProductRelatedDetail loanProductRelatedDetail, final DataValidatorBuilder baseDataValidator) {
boolean numberOfRepaymentsUpdated = false;
boolean minNumberOfRepaymentsUpdated = false;
boolean maxNumberOfRepaymentsUpdated = false;
String numberOfRepaymentsParameterName = "numberOfRepayments";
Integer numberOfRepayments = null;
if (fromApiJsonHelper.parameterExists(numberOfRepaymentsParameterName, element)) {
numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed(numberOfRepaymentsParameterName, element);
numberOfRepaymentsUpdated = true;
}else{
numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
}
String minNumberOfRepaymentsParameterName = "minNumberOfRepayments";
Integer minNumberOfRepayments = null;
if (fromApiJsonHelper.parameterExists(minNumberOfRepaymentsParameterName, element)) {
minNumberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed(minNumberOfRepaymentsParameterName, element);
minNumberOfRepaymentsUpdated = true;
}else{
minNumberOfRepayments = loanProductRelatedDetail.getMinNumberOfRepayments();
}
String maxNumberOfRepaymentsParameterName = "maxNumberOfRepayments";
Integer maxNumberOfRepayments = null;
if (fromApiJsonHelper.parameterExists(maxNumberOfRepaymentsParameterName, element)) {
maxNumberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed(maxNumberOfRepaymentsParameterName, element);
maxNumberOfRepaymentsUpdated = true;
}else{
maxNumberOfRepayments = loanProductRelatedDetail.getMaxNumberOfRepayments();
}
if(minNumberOfRepaymentsUpdated){
baseDataValidator.reset().parameter(minNumberOfRepaymentsParameterName).value(minNumberOfRepayments).ignoreIfNull().notGreaterThanMax(maxNumberOfRepayments);
}
if(maxNumberOfRepaymentsUpdated){
baseDataValidator.reset().parameter(maxNumberOfRepaymentsParameterName).value(maxNumberOfRepayments).notLessThanMin(minNumberOfRepayments);
}
if(numberOfRepaymentsUpdated || minNumberOfRepaymentsUpdated || maxNumberOfRepaymentsUpdated){
if(maxNumberOfRepayments != null && maxNumberOfRepayments.compareTo(0) == 1){
if(minNumberOfRepayments != null && minNumberOfRepayments.compareTo(0) == 1){
baseDataValidator.reset().parameter(numberOfRepaymentsParameterName).value(numberOfRepayments).inMinMaxRange(minNumberOfRepayments, maxNumberOfRepayments);
}else{
baseDataValidator.reset().parameter(numberOfRepaymentsParameterName).value(numberOfRepayments).notGreaterThanMax(maxNumberOfRepayments);
}
}else if(minNumberOfRepayments != null && minNumberOfRepayments.compareTo(0) == 1){
baseDataValidator.reset().parameter(numberOfRepaymentsParameterName).value(numberOfRepayments).notLessThanMin(minNumberOfRepayments);
}
}
}
private void validateNominalInterestRatePerPeriodMinMaxConstraint(final JsonElement element, final LoanProductRelatedDetail loanProductRelatedDetail, final DataValidatorBuilder baseDataValidator) {
boolean iRPUpdated = false;
boolean minIRPUpdated = false;
boolean maxIRPUpdated = false;
String interestRatePerPeriodParameterName = "interestRatePerPeriod";
BigDecimal interestRatePerPeriod = null;
if (fromApiJsonHelper.parameterExists(interestRatePerPeriodParameterName, element)) {
interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(interestRatePerPeriodParameterName, element);
iRPUpdated = true;
}else{
interestRatePerPeriod = loanProductRelatedDetail.getNominalInterestRatePerPeriod();
}
String minInterestRatePerPeriodParameterName = "minInterestRatePerPeriod";
BigDecimal minInterestRatePerPeriod = null;
if (fromApiJsonHelper.parameterExists(minInterestRatePerPeriodParameterName, element)) {
minInterestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minInterestRatePerPeriodParameterName, element);
minIRPUpdated = true;
}else{
minInterestRatePerPeriod = loanProductRelatedDetail.getMinNominalInterestRatePerPeriod();
}
String maxInterestRatePerPeriodParameterName = "maxInterestRatePerPeriod";
BigDecimal maxInterestRatePerPeriod = null;
if (fromApiJsonHelper.parameterExists(maxInterestRatePerPeriodParameterName, element)) {
maxInterestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxInterestRatePerPeriodParameterName, element);
maxIRPUpdated = true;
}else{
maxInterestRatePerPeriod = loanProductRelatedDetail.getMaxNominalInterestRatePerPeriod();
}
if(minIRPUpdated){
baseDataValidator.reset().parameter(minInterestRatePerPeriodParameterName).value(minInterestRatePerPeriod).ignoreIfNull().notGreaterThanMax(maxInterestRatePerPeriod);
}
if(maxIRPUpdated){
baseDataValidator.reset().parameter(maxInterestRatePerPeriodParameterName).value(maxInterestRatePerPeriod).ignoreIfNull().notLessThanMin(minInterestRatePerPeriod);
}
if(iRPUpdated || minIRPUpdated || maxIRPUpdated){
if(maxInterestRatePerPeriod != null){
if(minInterestRatePerPeriod != null){
baseDataValidator.reset().parameter(interestRatePerPeriodParameterName).value(interestRatePerPeriod).inMinAndMaxAmountRange(minInterestRatePerPeriod, maxInterestRatePerPeriod);
}else{
baseDataValidator.reset().parameter(interestRatePerPeriodParameterName).value(interestRatePerPeriod).notGreaterThanMax(maxInterestRatePerPeriod);
}
}else if(minInterestRatePerPeriod != null){
baseDataValidator.reset().parameter(interestRatePerPeriodParameterName).value(interestRatePerPeriod).notLessThanMin(minInterestRatePerPeriod);
}
}
}
private boolean isCashBasedAccounting(final Integer accountingRuleType) { private boolean isCashBasedAccounting(final Integer accountingRuleType) {
return AccountingRuleType.CASH_BASED.getValue().equals(accountingRuleType); return AccountingRuleType.CASH_BASED.getValue().equals(accountingRuleType);
} }
@@ -97,9 +97,9 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
return "lp.id as id, lp.fund_id as fundId, f.name as fundName, lp.loan_transaction_strategy_id as transactionStrategyId, ltps.name as transactionStrategyName, " return "lp.id as id, lp.fund_id as fundId, f.name as fundName, lp.loan_transaction_strategy_id as transactionStrategyId, ltps.name as transactionStrategyName, "
+ "lp.name as name, lp.description as description, " + "lp.name as name, lp.description as description, "
+ "lp.principal_amount as principal, lp.min_principal_amount as minPrincipal, lp.max_principal_amount as maxPrincipal, lp.currency_code as currencyCode, lp.currency_digits as currencyDigits, " + "lp.principal_amount as principal, lp.min_principal_amount as minPrincipal, lp.max_principal_amount as maxPrincipal, lp.currency_code as currencyCode, lp.currency_digits as currencyDigits, "
+ "lp.nominal_interest_rate_per_period as interestRatePerPeriod, lp.interest_period_frequency_enum as interestRatePerPeriodFreq, " + "lp.nominal_interest_rate_per_period as interestRatePerPeriod, lp.min_nominal_interest_rate_per_period as minInterestRatePerPeriod, lp.max_nominal_interest_rate_per_period as maxInterestRatePerPeriod, lp.interest_period_frequency_enum as interestRatePerPeriodFreq, "
+ "lp.annual_nominal_interest_rate as annualInterestRate, lp.interest_method_enum as interestMethod, lp.interest_calculated_in_period_enum as interestCalculationInPeriodMethod," + "lp.annual_nominal_interest_rate as annualInterestRate, lp.interest_method_enum as interestMethod, lp.interest_calculated_in_period_enum as interestCalculationInPeriodMethod,"
+ "lp.repay_every as repaidEvery, lp.repayment_period_frequency_enum as repaymentPeriodFrequency, lp.number_of_repayments as numberOfRepayments, " + "lp.repay_every as repaidEvery, lp.repayment_period_frequency_enum as repaymentPeriodFrequency, lp.number_of_repayments as numberOfRepayments, lp.min_number_of_repayments as minNumberOfRepayments, lp.max_number_of_repayments as maxNumberOfRepayments, "
+ "lp.amortization_method_enum as amortizationMethod, lp.arrearstolerance_amount as tolerance, " + "lp.amortization_method_enum as amortizationMethod, lp.arrearstolerance_amount as tolerance, "
+ "lp.accounting_type as accountingType, " + "lp.accounting_type as accountingType, "
+ "curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol " + "curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol "
@@ -135,12 +135,16 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
final BigDecimal tolerance = rs.getBigDecimal("tolerance"); final BigDecimal tolerance = rs.getBigDecimal("tolerance");
final Integer numberOfRepayments = JdbcSupport.getInteger(rs, "numberOfRepayments"); final Integer numberOfRepayments = JdbcSupport.getInteger(rs, "numberOfRepayments");
final Integer minNumberOfRepayments = JdbcSupport.getInteger(rs, "minNumberOfRepayments");
final Integer maxNumberOfRepayments = JdbcSupport.getInteger(rs, "maxNumberOfRepayments");
final Integer repaymentEvery = JdbcSupport.getInteger(rs, "repaidEvery"); final Integer repaymentEvery = JdbcSupport.getInteger(rs, "repaidEvery");
final Integer accountingRuleId = JdbcSupport.getInteger(rs, "accountingType"); final Integer accountingRuleId = JdbcSupport.getInteger(rs, "accountingType");
final EnumOptionData accountingRuleType = LoanEnumerations.accountingRuleType(accountingRuleId); final EnumOptionData accountingRuleType = LoanEnumerations.accountingRuleType(accountingRuleId);
final BigDecimal interestRatePerPeriod = rs.getBigDecimal("interestRatePerPeriod"); final BigDecimal interestRatePerPeriod = rs.getBigDecimal("interestRatePerPeriod");
final BigDecimal minInterestRatePerPeriod = rs.getBigDecimal("minInterestRatePerPeriod");
final BigDecimal maxInterestRatePerPeriod = rs.getBigDecimal("maxInterestRatePerPeriod");
final BigDecimal annualInterestRate = rs.getBigDecimal("annualInterestRate"); final BigDecimal annualInterestRate = rs.getBigDecimal("annualInterestRate");
final int repaymentFrequencyTypeId = JdbcSupport.getInteger(rs, "repaymentPeriodFrequency"); final int repaymentFrequencyTypeId = JdbcSupport.getInteger(rs, "repaymentPeriodFrequency");
@@ -160,7 +164,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
.interestCalculationPeriodType(interestCalculationPeriodTypeId); .interestCalculationPeriodType(interestCalculationPeriodTypeId);
return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance, return new LoanProductData(id, name, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, repaymentEvery, interestRatePerPeriod, annualInterestRate, repaymentFrequencyType, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType,
interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, fundId, fundName, interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, fundId, fundName,
transactionStrategyId, transactionStrategyName, this.charges, accountingRuleType); transactionStrategyId, transactionStrategyName, this.charges, accountingRuleType);
} }
@@ -137,6 +137,8 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
final LoanProduct product = this.loanProductRepository.findOne(loanProductId); final LoanProduct product = this.loanProductRepository.findOne(loanProductId);
if (product == null) { throw new LoanProductNotFoundException(loanProductId); } if (product == null) { throw new LoanProductNotFoundException(loanProductId); }
this.fromApiJsonDeserializer.validateMinMaxConstraints(command.parsedJson(), product.loanProductRelatedDetail(), "loanproduct");
final Map<String, Object> changes = product.update(command, this.aprCalculator); final Map<String, Object> changes = product.update(command, this.aprCalculator);
if (changes.containsKey("fundId")) { if (changes.containsKey("fundId")) {
@@ -26,6 +26,8 @@ public class LoanProductRelatedDetailTestHelper {
// 2% per month, 24% per year // 2% per month, 24% per year
BigDecimal defaultNominalInterestRatePerPeriod = BigDecimal.valueOf(Double.valueOf("2")); BigDecimal defaultNominalInterestRatePerPeriod = BigDecimal.valueOf(Double.valueOf("2"));
BigDecimal defaultMinNominalInterestRatePerPeriod = BigDecimal.valueOf(Double.valueOf("1"));
BigDecimal defaultMaxNominalInterestRatePerPeriod = BigDecimal.valueOf(Double.valueOf("10"));
PeriodFrequencyType interestPeriodFrequencyType = PeriodFrequencyType.MONTHS; PeriodFrequencyType interestPeriodFrequencyType = PeriodFrequencyType.MONTHS;
BigDecimal defaultAnnualNominalInterestRate = BigDecimal.valueOf(Double.valueOf("24")); BigDecimal defaultAnnualNominalInterestRate = BigDecimal.valueOf(Double.valueOf("24"));
@@ -35,13 +37,17 @@ public class LoanProductRelatedDetailTestHelper {
PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.MONTHS; PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.MONTHS;
Integer defaultNumberOfRepayments = Integer.valueOf(4); Integer defaultNumberOfRepayments = Integer.valueOf(4);
Integer defaultMinNumberOfRepayments = Integer.valueOf(2);
Integer defaultMaxNumberOfRepayments = Integer.valueOf(6);
AmortizationMethod amortizationMethod = AmortizationMethod.EQUAL_PRINCIPAL; AmortizationMethod amortizationMethod = AmortizationMethod.EQUAL_PRINCIPAL;
BigDecimal inArrearsTolerance = BigDecimal.ZERO; BigDecimal inArrearsTolerance = BigDecimal.ZERO;
return createLoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, return createLoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal,
defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType, defaultNominalInterestRatePerPeriod, defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod,
defaultNumberOfRepayments, amortizationMethod, inArrearsTolerance); interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery,
repaymentFrequencyType, defaultNumberOfRepayments, defaultMinNumberOfRepayments, defaultMaxNumberOfRepayments,
amortizationMethod, inArrearsTolerance);
} }
public static LoanProductRelatedDetail createSettingsForEqualInstallmentAmortizationQuarterly() { public static LoanProductRelatedDetail createSettingsForEqualInstallmentAmortizationQuarterly() {
@@ -52,6 +58,8 @@ public class LoanProductRelatedDetailTestHelper {
// 2% per month, 24% per year // 2% per month, 24% per year
BigDecimal defaultNominalInterestRatePerPeriod = BigDecimal.valueOf(Double.valueOf("2")); BigDecimal defaultNominalInterestRatePerPeriod = BigDecimal.valueOf(Double.valueOf("2"));
BigDecimal defaultMinNominalInterestRatePerPeriod = BigDecimal.valueOf(Double.valueOf("2"));
BigDecimal defaultMaxNominalInterestRatePerPeriod = BigDecimal.valueOf(Double.valueOf("2"));
PeriodFrequencyType interestPeriodFrequencyType = PeriodFrequencyType.MONTHS; PeriodFrequencyType interestPeriodFrequencyType = PeriodFrequencyType.MONTHS;
BigDecimal defaultAnnualNominalInterestRate = BigDecimal.valueOf(Double.valueOf("24")); BigDecimal defaultAnnualNominalInterestRate = BigDecimal.valueOf(Double.valueOf("24"));
@@ -61,13 +69,17 @@ public class LoanProductRelatedDetailTestHelper {
PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.MONTHS; PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.MONTHS;
Integer defaultNumberOfRepayments = Integer.valueOf(4); Integer defaultNumberOfRepayments = Integer.valueOf(4);
Integer defaultMinNumberOfRepayments = Integer.valueOf(4);
Integer defaultMaxNumberOfRepayments = Integer.valueOf(4);
AmortizationMethod amortizationMethod = AmortizationMethod.EQUAL_INSTALLMENTS; AmortizationMethod amortizationMethod = AmortizationMethod.EQUAL_INSTALLMENTS;
BigDecimal inArrearsTolerance = BigDecimal.ZERO; BigDecimal inArrearsTolerance = BigDecimal.ZERO;
return createLoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, return createLoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal,
defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType, defaultNominalInterestRatePerPeriod, defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod,
defaultNumberOfRepayments, amortizationMethod, inArrearsTolerance); interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery,
repaymentFrequencyType, defaultNumberOfRepayments, defaultMinNumberOfRepayments, defaultMaxNumberOfRepayments,
amortizationMethod, inArrearsTolerance);
} }
public static LoanProductRelatedDetail createSettingsForFlatQuarterly(final AmortizationMethod amortizationMethod) { public static LoanProductRelatedDetail createSettingsForFlatQuarterly(final AmortizationMethod amortizationMethod) {
@@ -79,6 +91,8 @@ public class LoanProductRelatedDetailTestHelper {
// 2% per month, 24% per year // 2% per month, 24% per year
BigDecimal defaultNominalInterestRatePerPeriod = BigDecimal.valueOf(Double.valueOf("2")); BigDecimal defaultNominalInterestRatePerPeriod = BigDecimal.valueOf(Double.valueOf("2"));
BigDecimal defaultMinNominalInterestRatePerPeriod = BigDecimal.valueOf(Double.valueOf("2"));
BigDecimal defaultMaxNominalInterestRatePerPeriod = BigDecimal.valueOf(Double.valueOf("2"));
PeriodFrequencyType interestPeriodFrequencyType = PeriodFrequencyType.MONTHS; PeriodFrequencyType interestPeriodFrequencyType = PeriodFrequencyType.MONTHS;
BigDecimal defaultAnnualNominalInterestRate = BigDecimal.valueOf(Double.valueOf("24")); BigDecimal defaultAnnualNominalInterestRate = BigDecimal.valueOf(Double.valueOf("24"));
@@ -88,12 +102,16 @@ public class LoanProductRelatedDetailTestHelper {
PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.MONTHS; PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.MONTHS;
Integer defaultNumberOfRepayments = Integer.valueOf(4); Integer defaultNumberOfRepayments = Integer.valueOf(4);
Integer defaultMinNumberOfRepayments = Integer.valueOf(4);
Integer defaultMaxNumberOfRepayments = Integer.valueOf(4);
BigDecimal inArrearsTolerance = BigDecimal.ZERO; BigDecimal inArrearsTolerance = BigDecimal.ZERO;
return createLoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, return createLoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal,
defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType, defaultNominalInterestRatePerPeriod, defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod,
defaultNumberOfRepayments, amortizationMethod, inArrearsTolerance); interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery,
repaymentFrequencyType, defaultNumberOfRepayments, defaultMinNumberOfRepayments, defaultMaxNumberOfRepayments,
amortizationMethod, inArrearsTolerance);
} }
public static LoanProductRelatedDetail createSettingsForIrregularFlatEveryFourMonths() { public static LoanProductRelatedDetail createSettingsForIrregularFlatEveryFourMonths() {
@@ -105,6 +123,8 @@ public class LoanProductRelatedDetailTestHelper {
// 2% per month, 24% per year // 2% per month, 24% per year
BigDecimal defaultNominalInterestRatePerPeriod = BigDecimal.valueOf(Double.valueOf("2")); BigDecimal defaultNominalInterestRatePerPeriod = BigDecimal.valueOf(Double.valueOf("2"));
BigDecimal defaultMinNominalInterestRatePerPeriod = BigDecimal.valueOf(Double.valueOf("2"));
BigDecimal defaultMaxNominalInterestRatePerPeriod = BigDecimal.valueOf(Double.valueOf("4"));
PeriodFrequencyType interestPeriodFrequencyType = PeriodFrequencyType.MONTHS; PeriodFrequencyType interestPeriodFrequencyType = PeriodFrequencyType.MONTHS;
BigDecimal defaultAnnualNominalInterestRate = BigDecimal.valueOf(Double.valueOf("24")); BigDecimal defaultAnnualNominalInterestRate = BigDecimal.valueOf(Double.valueOf("24"));
@@ -114,26 +134,31 @@ public class LoanProductRelatedDetailTestHelper {
PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.MONTHS; PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.MONTHS;
Integer defaultNumberOfRepayments = Integer.valueOf(2); Integer defaultNumberOfRepayments = Integer.valueOf(2);
Integer defaultMinNumberOfRepayments = Integer.valueOf(2);
Integer defaultMaxNumberOfRepayments = Integer.valueOf(2);
BigDecimal inArrearsTolerance = BigDecimal.ZERO; BigDecimal inArrearsTolerance = BigDecimal.ZERO;
AmortizationMethod amortizationMethod = AmortizationMethod.EQUAL_PRINCIPAL; AmortizationMethod amortizationMethod = AmortizationMethod.EQUAL_PRINCIPAL;
return createLoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal, return createLoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal,
defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, defaultNominalInterestRatePerPeriod, defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod, interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod,
interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType, defaultNumberOfRepayments, amortizationMethod, interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType, defaultNumberOfRepayments, defaultMinNumberOfRepayments, defaultMaxNumberOfRepayments, amortizationMethod,
inArrearsTolerance); inArrearsTolerance);
} }
private static LoanProductRelatedDetail createLoanProductRelatedDetail(MonetaryCurrency currency, BigDecimal defaultPrincipal, private static LoanProductRelatedDetail createLoanProductRelatedDetail(MonetaryCurrency currency, BigDecimal defaultPrincipal,
BigDecimal defaultMinPrincipal, BigDecimal defaultMaxPrincipal, BigDecimal defaultNominalInterestRatePerPeriod, BigDecimal defaultMinPrincipal, BigDecimal defaultMaxPrincipal, BigDecimal defaultNominalInterestRatePerPeriod,
BigDecimal defaultMinNominalInterestRatePerPeriod, BigDecimal defaultMaxNominalInterestRatePerPeriod,
PeriodFrequencyType interestPeriodFrequencyType, BigDecimal defaultAnnualNominalInterestRate, InterestMethod interestMethod, PeriodFrequencyType interestPeriodFrequencyType, BigDecimal defaultAnnualNominalInterestRate, InterestMethod interestMethod,
InterestCalculationPeriodMethod interestCalculationPeriodMethod, Integer repayEvery, InterestCalculationPeriodMethod interestCalculationPeriodMethod, Integer repayEvery,
PeriodFrequencyType repaymentFrequencyType, Integer defaultNumberOfRepayments, AmortizationMethod amortizationMethod, PeriodFrequencyType repaymentFrequencyType, Integer defaultNumberOfRepayments, Integer defaultMinNumberOfRepayments,
BigDecimal inArrearsTolerance) { Integer defaultMaxNumberOfRepayments, AmortizationMethod amortizationMethod, BigDecimal inArrearsTolerance) {
return new LoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, return new LoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal,
defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType, defaultNominalInterestRatePerPeriod, defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod,
defaultNumberOfRepayments, amortizationMethod, inArrearsTolerance); interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery,
repaymentFrequencyType, defaultNumberOfRepayments, defaultMinNumberOfRepayments, defaultMaxNumberOfRepayments,
amortizationMethod, inArrearsTolerance);
} }
} }