MIFOSX-282: remove min and max fields from loan table

This commit is contained in:
ashok-conflux
2013-04-13 18:08:51 +05:30
parent 45bf43de5e
commit debce5655f
13 changed files with 275 additions and 306 deletions
@@ -0,0 +1,7 @@
ALTER TABLE `m_loan`
DROP COLUMN `min_principal_amount`,
DROP COLUMN `max_principal_amount`,
DROP COLUMN `min_nominal_interest_rate_per_period`,
DROP COLUMN `max_nominal_interest_rate_per_period`,
DROP COLUMN `min_number_of_repayments`,
DROP COLUMN `max_number_of_repayments`;
@@ -668,6 +668,10 @@ public class Loan extends AbstractPersistable<Long> {
return this.client;
}
public LoanProduct loanProduct(){
return this.loanProduct;
}
public LoanProductRelatedDetail repaymentScheduleDetail() {
return this.loanRepaymentScheduleDetail;
}
@@ -1318,12 +1322,8 @@ public class Loan extends AbstractPersistable<Long> {
final LoanScheduleGenerator loanScheduleGenerator = new DefaultLoanScheduleGeneratorFactory().create(interestMethod);
final BigDecimal principal = this.loanRepaymentScheduleDetail.getPrincipal().getAmount();
final BigDecimal minPrincipal = this.loanRepaymentScheduleDetail.getMinPrincipal().getAmount();
final BigDecimal maxPrincipal = this.loanRepaymentScheduleDetail.getMaxPrincipal().getAmount();
final BigDecimal inArrearsTolerance = this.loanRepaymentScheduleDetail.getInArrearsTolerance().getAmount();
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 BigDecimal defaultAnnualNominalInterestRate = this.loanRepaymentScheduleDetail.getAnnualNominalInterestRate();
@@ -1332,18 +1332,15 @@ public class Loan extends AbstractPersistable<Long> {
final Integer repaymentEvery = this.loanRepaymentScheduleDetail.getRepayEvery();
final PeriodFrequencyType repaymentPeriodFrequencyType = this.loanRepaymentScheduleDetail.getRepaymentPeriodFrequencyType();
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 Integer loanTermFrequency = this.termFrequency;
final PeriodFrequencyType loanTermPeriodFrequencyType = PeriodFrequencyType.fromInt(this.termPeriodFrequencyType);
final LoanSchedule loanSchedule = new LoanSchedule(loanScheduleGenerator, applicationCurrency, principal, minPrincipal,
maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestRatePeriodFrequencyType,
defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery,
repaymentPeriodFrequencyType, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, amortizationMethod,
loanTermFrequency, loanTermPeriodFrequencyType, setOfLoanCharges(), this.getDisbursementDate(),
this.getExpectedFirstRepaymentOnDate(), this.getInterestChargedFromDate(), inArrearsTolerance);
final LoanSchedule loanSchedule = new LoanSchedule(loanScheduleGenerator, applicationCurrency, principal, interestRatePerPeriod,
interestRatePeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod,
repaymentEvery, repaymentPeriodFrequencyType, numberOfRepayments, amortizationMethod, loanTermFrequency,
loanTermPeriodFrequencyType, setOfLoanCharges(), this.getDisbursementDate(), this.getExpectedFirstRepaymentOnDate(),
this.getInterestChargedFromDate(), inArrearsTolerance);
final LoanScheduleData generatedData = loanSchedule.generate();
@@ -27,11 +27,7 @@ public final class LoanSchedule {
private final LoanScheduleGenerator loanScheduleGenerator;
private final ApplicationCurrency applicationCurrency;
private final BigDecimal principal;
private final BigDecimal minPrincipal;
private final BigDecimal maxPrincipal;
private final BigDecimal nominalInterestRatePerPeriod;
private final BigDecimal minNominalInterestRatePerPeriod;
private final BigDecimal maxNominalInterestRatePerPeriod;
private final PeriodFrequencyType interestRatePeriodFrequencyType;
private final BigDecimal nominalAnnualInterestRate;
private final InterestMethod interestMethod;
@@ -39,8 +35,6 @@ public final class LoanSchedule {
private final Integer repaymentEvery;
private final PeriodFrequencyType repaymentPeriodFrequencyType;
private final Integer numberOfRepayments;
private final Integer minNumberOfRepayments;
private final Integer maxNumberOfRepayments;
private final AmortizationMethod amortizationMethod;
private final Integer loanTermFrequency;
private final PeriodFrequencyType loanTermPeriodFrequencyType;
@@ -52,22 +46,17 @@ public final class LoanSchedule {
private final Set<LoanCharge> loanCharges;
public LoanSchedule(final LoanScheduleGenerator loanScheduleGenerator, final ApplicationCurrency applicationCurrency,
final BigDecimal principal, final BigDecimal minPrincipal, final BigDecimal maxPrincipal,
final BigDecimal nominalInterestRatePerPeriod, final BigDecimal minNominalInterestRatePerPeriod, final BigDecimal maxNominalInterestRatePerPeriod, final PeriodFrequencyType interestRatePeriodFrequencyType,
final BigDecimal nominalAnnualInterestRate, final InterestMethod interestMethod,
final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Integer repaymentEvery,
final PeriodFrequencyType repaymentPeriodFrequencyType, final Integer numberOfRepayments, final Integer minNumberOfRepayments, final Integer maxNumberOfRepayments,
final BigDecimal principal, final BigDecimal nominalInterestRatePerPeriod,
final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal nominalAnnualInterestRate,
final InterestMethod interestMethod, final InterestCalculationPeriodMethod interestCalculationPeriodMethod,
final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType, final Integer numberOfRepayments,
final AmortizationMethod amortizationMethod, final Integer loanTermFrequency,
final PeriodFrequencyType loanTermPeriodFrequencyType, final Set<LoanCharge> loanCharges, final LocalDate disbursementDate,
final LocalDate repaymentStartFromDate, final LocalDate interestChargedFromDate, final BigDecimal inArrearsTolerance) {
this.loanScheduleGenerator = loanScheduleGenerator;
this.applicationCurrency = applicationCurrency;
this.principal = principal;
this.minPrincipal = minPrincipal;
this.maxPrincipal = maxPrincipal;
this.nominalInterestRatePerPeriod = nominalInterestRatePerPeriod;
this.minNominalInterestRatePerPeriod = minNominalInterestRatePerPeriod;
this.maxNominalInterestRatePerPeriod = maxNominalInterestRatePerPeriod;
this.interestRatePeriodFrequencyType = interestRatePeriodFrequencyType;
this.nominalAnnualInterestRate = nominalAnnualInterestRate;
this.interestMethod = interestMethod;
@@ -75,8 +64,6 @@ public final class LoanSchedule {
this.repaymentEvery = repaymentEvery;
this.repaymentPeriodFrequencyType = repaymentPeriodFrequencyType;
this.numberOfRepayments = numberOfRepayments;
this.minNumberOfRepayments = minNumberOfRepayments;
this.maxNumberOfRepayments = maxNumberOfRepayments;
this.amortizationMethod = amortizationMethod;
this.loanTermFrequency = loanTermFrequency;
this.loanTermPeriodFrequencyType = loanTermPeriodFrequencyType;
@@ -95,9 +82,9 @@ public final class LoanSchedule {
public LoanProductRelatedDetail loanProductRelatedDetail() {
final MonetaryCurrency currency = new MonetaryCurrency(applicationCurrency.getCode(), applicationCurrency.getDecimalPlaces());
return LoanProductRelatedDetail.createFrom(currency, principal, minPrincipal, maxPrincipal, nominalInterestRatePerPeriod, minNominalInterestRatePerPeriod, maxNominalInterestRatePerPeriod,
interestRatePeriodFrequencyType, nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod,
repaymentEvery, repaymentPeriodFrequencyType, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, amortizationMethod, this.inArrearsTolerance);
return LoanProductRelatedDetail.createFrom(currency, principal, nominalInterestRatePerPeriod, interestRatePeriodFrequencyType,
nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentPeriodFrequencyType,
numberOfRepayments, amortizationMethod, this.inArrearsTolerance);
}
public Integer getLoanTermFrequency() {
@@ -73,33 +73,7 @@ public class LoanScheduleAssembler {
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
final BigDecimal principal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element);
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 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 interestType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestType", element);
final Integer interestCalculationPeriodType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestCalculationPeriodType",
@@ -116,18 +90,6 @@ public class LoanScheduleAssembler {
final Integer repaymentEvery = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentEvery", element);
final Integer repaymentFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentFrequencyType", 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 PeriodFrequencyType repaymentPeriodFrequencyType = PeriodFrequencyType.fromInt(repaymentFrequencyType);
final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(amortizationType);
@@ -144,10 +106,10 @@ public class LoanScheduleAssembler {
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(interestMethod);
return new LoanSchedule(loanScheduleGenerator, applicationCurrency, principal, minPrincipal, maxPrincipal, interestRatePerPeriod,
minInterestRatePerPeriod, maxInterestRatePerPeriod, interestRatePeriodFrequencyType, defaultAnnualNominalInterestRate,
interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentPeriodFrequencyType, numberOfRepayments,
minNumberOfRepayments, maxNumberOfRepayments, amortizationMethod, loanTermFrequency, loanTermPeriodFrequencyType,
loanCharges, expectedDisbursementDate, repaymentsStartingFromDate, interestChargedFromDate, inArrearsTolerance);
return new LoanSchedule(loanScheduleGenerator, applicationCurrency, principal, interestRatePerPeriod,
interestRatePeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod,
repaymentEvery, repaymentPeriodFrequencyType, numberOfRepayments, amortizationMethod, loanTermFrequency,
loanTermPeriodFrequencyType, loanCharges, expectedDisbursementDate, repaymentsStartingFromDate, interestChargedFromDate,
inArrearsTolerance);
}
}
@@ -23,6 +23,7 @@ import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.mifosplatform.portfolio.loanproduct.serialization.LoanProductCommandFromApiJsonDeserializer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -49,13 +50,16 @@ public final class LoanApplicationCommandFromApiJsonHelper {
));
private final FromJsonHelper fromApiJsonHelper;
private final LoanProductCommandFromApiJsonDeserializer loanProductCommandFromApiJsonDeserializer;
@Autowired
public LoanApplicationCommandFromApiJsonHelper(final FromJsonHelper fromApiJsonHelper) {
public LoanApplicationCommandFromApiJsonHelper(final FromJsonHelper fromApiJsonHelper, final LoanProductCommandFromApiJsonDeserializer loanProductCommandFromApiJsonDeserializer) {
this.fromApiJsonHelper = fromApiJsonHelper;
this.loanProductCommandFromApiJsonDeserializer = loanProductCommandFromApiJsonDeserializer;
}
public void validateForCreate(final String json) {
public void validateForCreate(final String json, final LoanProduct loanProduct) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
@@ -281,6 +285,8 @@ public final class LoanApplicationCommandFromApiJsonHelper {
}
}
loanProductCommandFromApiJsonDeserializer.validateMinMaxConstraints(element, baseDataValidator, loanProduct);
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
@@ -593,19 +599,11 @@ public final class LoanApplicationCommandFromApiJsonHelper {
"Validation errors exist.", dataValidationErrors); }
}
public void validateMinMaxConstraintValues(final JsonElement element, final LoanProduct loanProduct){
public void validateMinMaxConstraintsForModification(final String json, final LoanProduct loanProduct) {
final JsonElement element = fromApiJsonHelper.parse(json);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
final BigDecimal minPrincipal = loanProduct.getMinPrincipalAmount().getAmount();
final BigDecimal maxPrincipal = loanProduct.getMaxPrincipalAmount().getAmount();
final String principalParameterName = "principal";
if (fromApiJsonHelper.parameterExists(principalParameterName, element)) {
final BigDecimal principal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(principalParameterName, element);
baseDataValidator.reset().parameter(principalParameterName).value(principal).notNull().positiveAmount().inMinAndMaxAmountRange(minPrincipal, maxPrincipal);
}
this.loanProductCommandFromApiJsonDeserializer.validateMinMaxConstraints(element, baseDataValidator, loanProduct);
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
@@ -57,7 +57,6 @@ import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
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.NoteRepository;
import org.mifosplatform.useradministration.domain.AppUser;
@@ -93,7 +92,6 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
private final CalendarRepository calendarRepository;
private final CalendarInstanceRepository calendarInstanceRepository;
private final LoanProductCommandFromApiJsonDeserializer loanProductCommandFromApiJsonDeserializer;
@Autowired
public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper,
@@ -105,8 +103,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
final LoanProductRepository loanProductRepository, final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory,
final LoanSummaryWrapper loanSummaryWrapper,
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
final CalendarRepository calendarRepository, final CalendarInstanceRepository calendarInstanceRepository,
final LoanProductCommandFromApiJsonDeserializer loanProductCommandFromApiJsonDeserializer) {
final CalendarRepository calendarRepository, final CalendarInstanceRepository calendarInstanceRepository) {
this.context = context;
this.fromJsonHelper = fromJsonHelper;
this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator;
@@ -125,7 +122,6 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
this.calendarRepository = calendarRepository;
this.calendarInstanceRepository = calendarInstanceRepository;
this.loanProductCommandFromApiJsonDeserializer = loanProductCommandFromApiJsonDeserializer;
}
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
@@ -139,8 +135,12 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
AppUser currentUser = context.authenticatedUser();
this.fromApiJsonDeserializer.validateForCreate(command.json());
final Long productId = fromJsonHelper.extractLongNamed("productId", command.parsedJson());
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
if (loanProduct == null) { throw new LoanProductNotFoundException(productId); }
this.fromApiJsonDeserializer.validateForCreate(command.json(), loanProduct);
//validate dates against calendar recurring dates
//get calendar
@@ -203,7 +203,6 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
}
final Loan existingLoanApplication = retrieveLoanBy(loanId);
this.loanProductCommandFromApiJsonDeserializer.validateMinMaxConstraints(command.parsedJson(), existingLoanApplication.repaymentScheduleDetail(), "loan");
if (!existingLoanApplication.isSubmittedAndPendingApproval()) { throw new LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified(
loanId); }
@@ -232,6 +231,9 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
existingLoanApplication.updateLoanProduct(loanProduct);
}
//validate min and maximum constraints
this.fromApiJsonDeserializer.validateMinMaxConstraintsForModification(command.json(), existingLoanApplication.loanProduct());
final String fundIdParamName = "fundId";
if (changes.containsKey(fundIdParamName)) {
@@ -46,7 +46,6 @@ import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
import org.mifosplatform.portfolio.loanproduct.serialization.LoanProductCommandFromApiJsonDeserializer;
import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -69,7 +68,6 @@ public class LoanAssembler {
private final FromJsonHelper fromApiJsonHelper;
private final LoanSummaryWrapper loanSummaryWrapper;
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
private final LoanProductCommandFromApiJsonDeserializer loanProductCommandFromApiJsonDeserializer;
@Autowired
public LoanAssembler(final FromJsonHelper fromApiJsonHelper, final LoanProductRepository loanProductRepository,
@@ -78,8 +76,7 @@ public class LoanAssembler {
final StaffRepository staffRepository, final CodeValueRepositoryWrapper codeValueRepository,
final LoanScheduleAssembler loanScheduleAssembler, final LoanChargeAssembler loanChargeAssembler,
final CollateralAssembler loanCollateralAssembler, final LoanSummaryWrapper loanSummaryWrapper,
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
final LoanProductCommandFromApiJsonDeserializer loanProductCommandFromApiJsonDeserializer) {
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory) {
this.fromApiJsonHelper = fromApiJsonHelper;
this.loanProductRepository = loanProductRepository;
this.clientRepository = clientRepository;
@@ -93,7 +90,6 @@ public class LoanAssembler {
this.loanCollateralAssembler = loanCollateralAssembler;
this.loanSummaryWrapper = loanSummaryWrapper;
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
this.loanProductCommandFromApiJsonDeserializer = loanProductCommandFromApiJsonDeserializer;
}
public Loan assembleFrom(final JsonCommand command, final AppUser currentUser) {
@@ -116,9 +112,6 @@ public class LoanAssembler {
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
if (loanProduct == null) { throw new LoanProductNotFoundException(productId); }
//validate min and max constraint parameters
this.loanProductCommandFromApiJsonDeserializer.validateMinMaxConstraints(element, loanProduct.loanProductRelatedDetail(), "loan");
final Fund fund = findFundByIdIfProvided(fundId);
final Staff loanOfficer = findLoanOfficerByIdIfProvided(loanOfficerId);
@@ -65,6 +65,9 @@ public class LoanProduct extends AbstractPersistable<Long> {
@Embedded
private final LoanProductRelatedDetail loanProductRelatedDetail;
@Embedded
private LoanProductMinMaxConstraints loanProductMinMaxConstraints;
@Column(name = "accounting_type", nullable = false)
private Integer accountingRule;
@@ -110,6 +113,7 @@ public class LoanProduct extends AbstractPersistable<Long> {
protected LoanProduct() {
this.loanProductRelatedDetail = null;
this.loanProductMinMaxConstraints = null;
}
public LoanProduct(final Fund fund, final LoanTransactionProcessingStrategy transactionProcessingStrategy, final String name,
@@ -136,12 +140,14 @@ public class LoanProduct extends AbstractPersistable<Long> {
this.charges = charges;
}
this.loanProductRelatedDetail = new LoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal,
defaultNominalInterestRatePerPeriod, defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod,
this.loanProductRelatedDetail = new LoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod,
interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery,
repaymentFrequencyType, defaultNumberOfInstallments, defaultMinNumberOfInstallments, defaultMaxNumberOfInstallments,
amortizationMethod, inArrearsTolerance);
repaymentFrequencyType, defaultNumberOfInstallments, amortizationMethod, inArrearsTolerance);
this.loanProductMinMaxConstraints = new LoanProductMinMaxConstraints(defaultMinPrincipal, defaultMaxPrincipal,
defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod, defaultMinNumberOfInstallments,
defaultMaxNumberOfInstallments);
if (accountingRuleType != null) {
this.accountingRule = accountingRuleType.getValue();
}
@@ -179,6 +185,7 @@ public class LoanProduct extends AbstractPersistable<Long> {
public Map<String, Object> update(final JsonCommand command, final AprCalculator aprCalculator) {
final Map<String, Object> actualChanges = this.loanProductRelatedDetail.update(command, aprCalculator);
actualChanges.putAll(this.loanProductMinMaxConstraints().update(command));
final String accountingTypeParamName = "accountingRule";
if (command.isChangeInIntegerParameterNamed(accountingTypeParamName, this.accountingRule)) {
@@ -246,11 +253,11 @@ public class LoanProduct extends AbstractPersistable<Long> {
}
public Money getMinPrincipalAmount(){
return this.loanProductRelatedDetail.getMinPrincipal();
return Money.of(this.loanProductRelatedDetail.getCurrency(), this.loanProductMinMaxConstraints().getMinPrincipal());
}
public Money getMaxPrincipalAmount(){
return this.loanProductRelatedDetail.getMaxPrincipal();
return Money.of(this.loanProductRelatedDetail.getCurrency(), this.loanProductMinMaxConstraints().getMaxPrincipal());
}
public BigDecimal getNominalInterestRatePerPeriod() {
@@ -258,26 +265,34 @@ public class LoanProduct extends AbstractPersistable<Long> {
}
public BigDecimal getMinNominalInterestRatePerPeriod() {
return this.loanProductRelatedDetail.getMinNominalInterestRatePerPeriod();
return this.loanProductMinMaxConstraints().getMinNominalInterestRatePerPeriod();
}
public BigDecimal getMaxNominalInterestRatePerPeriod(){
return this.loanProductRelatedDetail.getMaxNominalInterestRatePerPeriod();
return this.loanProductMinMaxConstraints().getMaxNominalInterestRatePerPeriod();
}
public Integer getNumberOfRepayments(){
return this.loanProductRelatedDetail.getNumberOfRepayments();
return this.loanProductRelatedDetail().getNumberOfRepayments();
}
public Integer getMinNumberOfRepayments() {
return this.loanProductRelatedDetail.getMinNumberOfRepayments();
return this.loanProductMinMaxConstraints().getMinNumberOfRepayments();
}
public Integer getMaxNumberOfRepayments() {
return this.loanProductRelatedDetail.getMaxNumberOfRepayments();
return this.loanProductMinMaxConstraints().getMaxNumberOfRepayments();
}
public LoanProductRelatedDetail loanProductRelatedDetail(){
return this.loanProductRelatedDetail;
}
public LoanProductMinMaxConstraints loanProductMinMaxConstraints() {
//If all min and max fields are null then loanProductMinMaxConstraints initialising to null
//Reset LoanProductMinMaxConstraints with null values.
this.loanProductMinMaxConstraints = (this.loanProductMinMaxConstraints == null) ? new LoanProductMinMaxConstraints(null, null, null, null, null, null)
: this.loanProductMinMaxConstraints;
return loanProductMinMaxConstraints;
}
}
@@ -0,0 +1,150 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.loanproduct.domain;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
/**
* LoanProductMinMaxConstraints encapsulates all the Min and Max details of a
* {@link LoanProduct}.
*/
@Embeddable
public class LoanProductMinMaxConstraints {
@Column(name = "min_principal_amount", scale = 6, precision = 19, nullable = true)
private BigDecimal minPrincipal;
@Column(name = "max_principal_amount", scale = 6, precision = 19, nullable = true)
private BigDecimal maxPrincipal;
@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;
@Column(name = "min_number_of_repayments", nullable = true)
private Integer minNumberOfRepayments;
@Column(name = "max_number_of_repayments", nullable = true)
private Integer maxNumberOfRepayments;
public static LoanProductMinMaxConstraints createFrom(final BigDecimal minPrincipal, final BigDecimal maxPrincipal,
final BigDecimal minNominalInterestRatePerPeriod, final BigDecimal maxNominalInterestRatePerPeriod,
final Integer minNumberOfRepayments, final Integer maxNumberOfRepayments) {
return new LoanProductMinMaxConstraints(minPrincipal, maxPrincipal, minNominalInterestRatePerPeriod,
maxNominalInterestRatePerPeriod, minNumberOfRepayments, maxNumberOfRepayments);
}
protected LoanProductMinMaxConstraints() {
//
}
public LoanProductMinMaxConstraints(final BigDecimal defaultMinPrincipal, final BigDecimal defaultMaxPrincipal,
final BigDecimal defaultMinNominalInterestRatePerPeriod, final BigDecimal defaultMaxNominalInterestRatePerPeriod,
final Integer defaultMinNumberOfRepayments, final Integer defaultMaxNumberOfRepayments) {
this.minPrincipal = defaultMinPrincipal;
this.maxPrincipal = defaultMaxPrincipal;
this.minNominalInterestRatePerPeriod = defaultMinNominalInterestRatePerPeriod;
this.maxNominalInterestRatePerPeriod = defaultMaxNominalInterestRatePerPeriod;
this.minNumberOfRepayments = defaultMinNumberOfRepayments;
this.maxNumberOfRepayments = defaultMaxNumberOfRepayments;
}
public Map<String, Object> update(final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(20);
final String localeAsInput = command.locale();
final String minPrincipalParamName = "minPrincipal";
if (command.isChangeInBigDecimalParameterNamedWithNullCheck(minPrincipalParamName, this.minPrincipal)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minPrincipalParamName);
actualChanges.put(minPrincipalParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.minPrincipal = newValue;
}
final String maxPrincipalParamName = "maxPrincipal";
if (command.isChangeInBigDecimalParameterNamedWithNullCheck(maxPrincipalParamName, this.maxPrincipal)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(maxPrincipalParamName);
actualChanges.put(maxPrincipalParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.maxPrincipal = 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 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;
}
return actualChanges;
}
public BigDecimal getMinPrincipal() {
return this.minPrincipal;
}
public BigDecimal getMaxPrincipal() {
return this.maxPrincipal;
}
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 Integer getMinNumberOfRepayments() {
return minNumberOfRepayments;
}
public Integer getMaxNumberOfRepayments() {
return maxNumberOfRepayments;
}
}
@@ -34,20 +34,8 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
@Column(name = "principal_amount", scale = 6, precision = 19, nullable = false)
private BigDecimal principal;
@Column(name = "min_principal_amount", scale = 6, precision = 19, nullable = true)
private BigDecimal minPrincipal;
@Column(name = "max_principal_amount", scale = 6, precision = 19, nullable = true)
private BigDecimal maxPrincipal;
@Column(name = "nominal_interest_rate_per_period", scale = 6, precision = 19, nullable = false)
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 -
// requires sql patch for existing users of software.
@@ -81,12 +69,6 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
@Column(name = "number_of_repayments", nullable = false)
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 -
// requires sql patch for existing users of software.
@@ -98,18 +80,15 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
private BigDecimal inArrearsTolerance;
public static LoanProductRelatedDetail createFrom(final MonetaryCurrency currency, final BigDecimal principal,
final BigDecimal minPrincipal, final BigDecimal maxPrincipal, final BigDecimal nominalInterestRatePerPeriod,
final BigDecimal minNominalInterestRatePerPeriod, final BigDecimal maxNominalInterestRatePerPeriod,
final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal nominalAnnualInterestRate,
final InterestMethod interestMethod, final InterestCalculationPeriodMethod interestCalculationPeriodMethod,
final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType, final Integer numberOfRepayments,
final Integer minNumberOfRepayments, final Integer maxNumberOfRepayments, final AmortizationMethod amortizationMethod,
final BigDecimal inArrearsTolerance) {
final BigDecimal nominalInterestRatePerPeriod, final PeriodFrequencyType interestRatePeriodFrequencyType,
final BigDecimal nominalAnnualInterestRate, final InterestMethod interestMethod,
final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Integer repaymentEvery,
final PeriodFrequencyType repaymentPeriodFrequencyType, final Integer numberOfRepayments,
final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance) {
return new LoanProductRelatedDetail(currency, principal, minPrincipal, maxPrincipal, nominalInterestRatePerPeriod,
minNominalInterestRatePerPeriod, maxNominalInterestRatePerPeriod, interestRatePeriodFrequencyType,
return new LoanProductRelatedDetail(currency, principal, nominalInterestRatePerPeriod, interestRatePeriodFrequencyType,
nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentPeriodFrequencyType,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, amortizationMethod, inArrearsTolerance);
numberOfRepayments, amortizationMethod, inArrearsTolerance);
}
protected LoanProductRelatedDetail() {
@@ -117,21 +96,14 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
}
public LoanProductRelatedDetail(final MonetaryCurrency currency, final BigDecimal defaultPrincipal,
final BigDecimal defaultMinPrincipal, final BigDecimal defaultMaxPrincipal,
final BigDecimal defaultNominalInterestRatePerPeriod, final BigDecimal defaultMinNominalInterestRatePerPeriod,
final BigDecimal defaultMaxNominalInterestRatePerPeriod, final PeriodFrequencyType interestPeriodFrequencyType,
final BigDecimal defaultNominalInterestRatePerPeriod,final PeriodFrequencyType interestPeriodFrequencyType,
final BigDecimal defaultAnnualNominalInterestRate, final InterestMethod interestMethod,
final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Integer repayEvery,
final PeriodFrequencyType repaymentFrequencyType, final Integer defaultNumberOfRepayments,
final Integer defaultMinNumberOfRepayments, final Integer defaultMaxNumberOfRepayments,
final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance) {
this.currency = currency;
this.principal = defaultPrincipal;
this.minPrincipal = defaultMinPrincipal;
this.maxPrincipal = defaultMaxPrincipal;
this.nominalInterestRatePerPeriod = defaultNominalInterestRatePerPeriod;
this.minNominalInterestRatePerPeriod = defaultMinNominalInterestRatePerPeriod;
this.maxNominalInterestRatePerPeriod = defaultMaxNominalInterestRatePerPeriod;
this.interestPeriodFrequencyType = interestPeriodFrequencyType;
this.annualNominalInterestRate = defaultAnnualNominalInterestRate;
this.interestMethod = interestMethod;
@@ -139,8 +111,6 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
this.repayEvery = repayEvery;
this.repaymentPeriodFrequencyType = repaymentFrequencyType;
this.numberOfRepayments = defaultNumberOfRepayments;
this.minNumberOfRepayments = defaultMinNumberOfRepayments;
this.maxNumberOfRepayments = defaultMaxNumberOfRepayments;
this.amortizationMethod = amortizationMethod;
if (inArrearsTolerance != null && BigDecimal.ZERO.compareTo(inArrearsTolerance) == 0) {
this.inArrearsTolerance = null;
@@ -156,14 +126,6 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
public Money getPrincipal() {
return Money.of(this.currency, this.principal);
}
public Money getMinPrincipal() {
return Money.of(this.currency, this.minPrincipal);
}
public Money getMaxPrincipal() {
return Money.of(this.currency, this.maxPrincipal);
}
public Money getInArrearsTolerance() {
return Money.of(this.currency, this.inArrearsTolerance);
@@ -172,17 +134,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
public BigDecimal getNominalInterestRatePerPeriod() {
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() {
return interestPeriodFrequencyType;
}
@@ -214,14 +166,6 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
return numberOfRepayments;
}
public Integer getMinNumberOfRepayments() {
return minNumberOfRepayments;
}
public Integer getMaxNumberOfRepayments() {
return maxNumberOfRepayments;
}
public AmortizationMethod getAmortizationMethod() {
return amortizationMethod;
}
@@ -264,22 +208,6 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
final String localeAsInput = command.locale();
final String minPrincipalParamName = "minPrincipal";
if (command.isChangeInBigDecimalParameterNamedWithNullCheck(minPrincipalParamName, this.minPrincipal)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minPrincipalParamName);
actualChanges.put(minPrincipalParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.minPrincipal = newValue;
}
final String maxPrincipalParamName = "maxPrincipal";
if (command.isChangeInBigDecimalParameterNamedWithNullCheck(maxPrincipalParamName, this.maxPrincipal)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(maxPrincipalParamName);
actualChanges.put(maxPrincipalParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.maxPrincipal = newValue;
}
final String principalParamName = "principal";
if (command.isChangeInBigDecimalParameterNamed(principalParamName, this.principal)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(principalParamName);
@@ -303,22 +231,6 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
actualChanges.put("locale", localeAsInput);
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";
if (command.isChangeInIntegerParameterNamed(numberOfRepaymentsParamName, this.numberOfRepayments)) {
@@ -343,22 +255,6 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
actualChanges.put("locale", localeAsInput);
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";
if (command.isChangeInBigDecimalParameterNamed(interestRatePerPeriodParamName, this.nominalInterestRatePerPeriod)) {
@@ -23,7 +23,7 @@ import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -261,7 +261,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateForUpdate(final String json) {
public void validateForUpdate(final String json, final LoanProduct loanProduct) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
@@ -445,23 +445,21 @@ public final class LoanProductCommandFromApiJsonDeserializer {
baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue())
.value(receivablePenaltyAccountId).ignoreIfNull().integerGreaterThanZero();
validateMinMaxConstraints(element, baseDataValidator, loanProduct);
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);
public void validateMinMaxConstraints(final JsonElement element, final DataValidatorBuilder baseDataValidator, final LoanProduct loanProduct){
validatePrincipalMinMaxConstraint(element, loanProductRelatedDetail, baseDataValidator);
validatePrincipalMinMaxConstraint(element, loanProduct, baseDataValidator);
validateNumberOfRepaymentsMinMaxConstraint(element, loanProductRelatedDetail, baseDataValidator);
validateNumberOfRepaymentsMinMaxConstraint(element, loanProduct, baseDataValidator);
validateNominalInterestRatePerPeriodMinMaxConstraint(element, loanProductRelatedDetail, baseDataValidator);
throwExceptionIfValidationWarningsExist(dataValidationErrors);
validateNominalInterestRatePerPeriodMinMaxConstraint(element, loanProduct, baseDataValidator);
}
private void validatePrincipalMinMaxConstraint(final JsonElement element, final LoanProductRelatedDetail loanProductRelatedDetail, final DataValidatorBuilder baseDataValidator) {
private void validatePrincipalMinMaxConstraint(final JsonElement element, final LoanProduct loanProduct, final DataValidatorBuilder baseDataValidator) {
boolean principalUpdated = false;
boolean minPrincipalUpdated = false;
@@ -472,7 +470,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
principalAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(principalParameterName, element);
principalUpdated = true;
}else{
principalAmount = loanProductRelatedDetail.getPrincipal().getAmount();
principalAmount = loanProduct.getPrincipalAmount().getAmount();
}
String minPrincipalParameterName = "minPrincipal";
@@ -481,7 +479,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
minPrincipalAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minPrincipalParameterName, element);
minPrincipalUpdated = true;
}else{
minPrincipalAmount = loanProductRelatedDetail.getMinPrincipal().getAmount();
minPrincipalAmount = loanProduct.getMinPrincipalAmount().getAmount();
}
String maxPrincipalParameterName = "maxPrincipal";
@@ -490,7 +488,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
maxPrincipalAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxPrincipalParameterName, element);
maxPrincipalUpdated = true;
}else{
maxPrincipalAmount = loanProductRelatedDetail.getMaxPrincipal().getAmount();
maxPrincipalAmount = loanProduct.getMaxPrincipalAmount().getAmount();
}
if(minPrincipalUpdated){
@@ -515,7 +513,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
}
}
private void validateNumberOfRepaymentsMinMaxConstraint(final JsonElement element, final LoanProductRelatedDetail loanProductRelatedDetail, final DataValidatorBuilder baseDataValidator) {
private void validateNumberOfRepaymentsMinMaxConstraint(final JsonElement element, final LoanProduct loanProduct, final DataValidatorBuilder baseDataValidator) {
boolean numberOfRepaymentsUpdated = false;
boolean minNumberOfRepaymentsUpdated = false;
boolean maxNumberOfRepaymentsUpdated = false;
@@ -526,7 +524,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed(numberOfRepaymentsParameterName, element);
numberOfRepaymentsUpdated = true;
}else{
numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
numberOfRepayments = loanProduct.getNumberOfRepayments();
}
String minNumberOfRepaymentsParameterName = "minNumberOfRepayments";
@@ -535,7 +533,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
minNumberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed(minNumberOfRepaymentsParameterName, element);
minNumberOfRepaymentsUpdated = true;
}else{
minNumberOfRepayments = loanProductRelatedDetail.getMinNumberOfRepayments();
minNumberOfRepayments = loanProduct.getMinNumberOfRepayments();
}
String maxNumberOfRepaymentsParameterName = "maxNumberOfRepayments";
@@ -544,7 +542,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
maxNumberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed(maxNumberOfRepaymentsParameterName, element);
maxNumberOfRepaymentsUpdated = true;
}else{
maxNumberOfRepayments = loanProductRelatedDetail.getMaxNumberOfRepayments();
maxNumberOfRepayments = loanProduct.getMaxNumberOfRepayments();
}
if(minNumberOfRepaymentsUpdated){
@@ -568,7 +566,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
}
}
private void validateNominalInterestRatePerPeriodMinMaxConstraint(final JsonElement element, final LoanProductRelatedDetail loanProductRelatedDetail, final DataValidatorBuilder baseDataValidator) {
private void validateNominalInterestRatePerPeriodMinMaxConstraint(final JsonElement element, final LoanProduct loanProduct, final DataValidatorBuilder baseDataValidator) {
boolean iRPUpdated = false;
boolean minIRPUpdated = false;
@@ -580,7 +578,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(interestRatePerPeriodParameterName, element);
iRPUpdated = true;
}else{
interestRatePerPeriod = loanProductRelatedDetail.getNominalInterestRatePerPeriod();
interestRatePerPeriod = loanProduct.getNominalInterestRatePerPeriod();
}
String minInterestRatePerPeriodParameterName = "minInterestRatePerPeriod";
@@ -589,7 +587,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
minInterestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minInterestRatePerPeriodParameterName, element);
minIRPUpdated = true;
}else{
minInterestRatePerPeriod = loanProductRelatedDetail.getMinNominalInterestRatePerPeriod();
minInterestRatePerPeriod = loanProduct.getMinNominalInterestRatePerPeriod();
}
String maxInterestRatePerPeriodParameterName = "maxInterestRatePerPeriod";
@@ -598,7 +596,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
maxInterestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxInterestRatePerPeriodParameterName, element);
maxIRPUpdated = true;
}else{
maxInterestRatePerPeriod = loanProductRelatedDetail.getMaxNominalInterestRatePerPeriod();
maxInterestRatePerPeriod = loanProduct.getMaxNominalInterestRatePerPeriod();
}
if(minIRPUpdated){
@@ -132,12 +132,10 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
try {
this.context.authenticatedUser();
this.fromApiJsonDeserializer.validateForUpdate(command.json());
final LoanProduct product = this.loanProductRepository.findOne(loanProductId);
if (product == null) { throw new LoanProductNotFoundException(loanProductId); }
this.fromApiJsonDeserializer.validateMinMaxConstraints(command.parsedJson(), product.loanProductRelatedDetail(), "loanproduct");
this.fromApiJsonDeserializer.validateForUpdate(command.json(), product);
final Map<String, Object> changes = product.update(command, this.aprCalculator);
@@ -21,13 +21,9 @@ public class LoanProductRelatedDetailTestHelper {
MonetaryCurrency currency = new MonetaryCurrencyBuilder().withCode("USD").withDigitsAfterDecimal(2).build();
BigDecimal defaultPrincipal = BigDecimal.valueOf(Double.valueOf("200000"));
BigDecimal defaultMinPrincipal = BigDecimal.valueOf(Double.valueOf("100000"));
BigDecimal defaultMaxPrincipal = BigDecimal.valueOf(Double.valueOf("250000"));
// 2% per month, 24% per year
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;
BigDecimal defaultAnnualNominalInterestRate = BigDecimal.valueOf(Double.valueOf("24"));
@@ -37,29 +33,21 @@ public class LoanProductRelatedDetailTestHelper {
PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.MONTHS;
Integer defaultNumberOfRepayments = Integer.valueOf(4);
Integer defaultMinNumberOfRepayments = Integer.valueOf(2);
Integer defaultMaxNumberOfRepayments = Integer.valueOf(6);
AmortizationMethod amortizationMethod = AmortizationMethod.EQUAL_PRINCIPAL;
BigDecimal inArrearsTolerance = BigDecimal.ZERO;
return createLoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal,
defaultNominalInterestRatePerPeriod, defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod,
interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery,
repaymentFrequencyType, defaultNumberOfRepayments, defaultMinNumberOfRepayments, defaultMaxNumberOfRepayments,
amortizationMethod, inArrearsTolerance);
return createLoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType,
defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType,
defaultNumberOfRepayments, amortizationMethod, inArrearsTolerance);
}
public static LoanProductRelatedDetail createSettingsForEqualInstallmentAmortizationQuarterly() {
MonetaryCurrency currency = new MonetaryCurrencyBuilder().withCode("USD").withDigitsAfterDecimal(2).build();
BigDecimal defaultPrincipal = BigDecimal.valueOf(Double.valueOf("200000"));
BigDecimal defaultMinPrincipal = BigDecimal.valueOf(Double.valueOf("100000"));
BigDecimal defaultMaxPrincipal = BigDecimal.valueOf(Double.valueOf("250000"));
// 2% per month, 24% per year
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;
BigDecimal defaultAnnualNominalInterestRate = BigDecimal.valueOf(Double.valueOf("24"));
@@ -69,30 +57,22 @@ public class LoanProductRelatedDetailTestHelper {
PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.MONTHS;
Integer defaultNumberOfRepayments = Integer.valueOf(4);
Integer defaultMinNumberOfRepayments = Integer.valueOf(4);
Integer defaultMaxNumberOfRepayments = Integer.valueOf(4);
AmortizationMethod amortizationMethod = AmortizationMethod.EQUAL_INSTALLMENTS;
BigDecimal inArrearsTolerance = BigDecimal.ZERO;
return createLoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal,
defaultNominalInterestRatePerPeriod, defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod,
interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery,
repaymentFrequencyType, defaultNumberOfRepayments, defaultMinNumberOfRepayments, defaultMaxNumberOfRepayments,
amortizationMethod, inArrearsTolerance);
return createLoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType,
defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType,
defaultNumberOfRepayments, amortizationMethod, inArrearsTolerance);
}
public static LoanProductRelatedDetail createSettingsForFlatQuarterly(final AmortizationMethod amortizationMethod) {
MonetaryCurrency currency = new MonetaryCurrencyBuilder().withCode("USD").withDigitsAfterDecimal(2).build();
BigDecimal defaultPrincipal = BigDecimal.valueOf(Double.valueOf("200000"));
BigDecimal defaultMinPrincipal = BigDecimal.valueOf(Double.valueOf("200000"));
BigDecimal defaultMaxPrincipal = BigDecimal.valueOf(Double.valueOf("200000"));
// 2% per month, 24% per year
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;
BigDecimal defaultAnnualNominalInterestRate = BigDecimal.valueOf(Double.valueOf("24"));
@@ -102,29 +82,21 @@ public class LoanProductRelatedDetailTestHelper {
PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.MONTHS;
Integer defaultNumberOfRepayments = Integer.valueOf(4);
Integer defaultMinNumberOfRepayments = Integer.valueOf(4);
Integer defaultMaxNumberOfRepayments = Integer.valueOf(4);
BigDecimal inArrearsTolerance = BigDecimal.ZERO;
return createLoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal,
defaultNominalInterestRatePerPeriod, defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod,
interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery,
repaymentFrequencyType, defaultNumberOfRepayments, defaultMinNumberOfRepayments, defaultMaxNumberOfRepayments,
amortizationMethod, inArrearsTolerance);
return createLoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType,
defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType,
defaultNumberOfRepayments, amortizationMethod, inArrearsTolerance);
}
public static LoanProductRelatedDetail createSettingsForIrregularFlatEveryFourMonths() {
MonetaryCurrency currency = new MonetaryCurrencyBuilder().withCode("KSH").withDigitsAfterDecimal(0).build();
BigDecimal defaultPrincipal = BigDecimal.valueOf(Double.valueOf("15000"));
BigDecimal defaultMinPrincipal = BigDecimal.valueOf(Double.valueOf("15000"));
BigDecimal defaultMaxPrincipal = BigDecimal.valueOf(Double.valueOf("15000"));
// 2% per month, 24% per year
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;
BigDecimal defaultAnnualNominalInterestRate = BigDecimal.valueOf(Double.valueOf("24"));
@@ -134,31 +106,25 @@ public class LoanProductRelatedDetailTestHelper {
PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.MONTHS;
Integer defaultNumberOfRepayments = Integer.valueOf(2);
Integer defaultMinNumberOfRepayments = Integer.valueOf(2);
Integer defaultMaxNumberOfRepayments = Integer.valueOf(2);
BigDecimal inArrearsTolerance = BigDecimal.ZERO;
AmortizationMethod amortizationMethod = AmortizationMethod.EQUAL_PRINCIPAL;
return createLoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal,
defaultNominalInterestRatePerPeriod, defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod, interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod,
interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType, defaultNumberOfRepayments, defaultMinNumberOfRepayments, defaultMaxNumberOfRepayments, amortizationMethod,
inArrearsTolerance);
return createLoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType,
defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType,
defaultNumberOfRepayments, amortizationMethod, inArrearsTolerance);
}
private static LoanProductRelatedDetail createLoanProductRelatedDetail(MonetaryCurrency currency, BigDecimal defaultPrincipal,
BigDecimal defaultMinPrincipal, BigDecimal defaultMaxPrincipal, BigDecimal defaultNominalInterestRatePerPeriod,
BigDecimal defaultMinNominalInterestRatePerPeriod, BigDecimal defaultMaxNominalInterestRatePerPeriod,
PeriodFrequencyType interestPeriodFrequencyType, BigDecimal defaultAnnualNominalInterestRate, InterestMethod interestMethod,
BigDecimal defaultNominalInterestRatePerPeriod, PeriodFrequencyType interestPeriodFrequencyType,
BigDecimal defaultAnnualNominalInterestRate, InterestMethod interestMethod,
InterestCalculationPeriodMethod interestCalculationPeriodMethod, Integer repayEvery,
PeriodFrequencyType repaymentFrequencyType, Integer defaultNumberOfRepayments, Integer defaultMinNumberOfRepayments,
Integer defaultMaxNumberOfRepayments, AmortizationMethod amortizationMethod, BigDecimal inArrearsTolerance) {
PeriodFrequencyType repaymentFrequencyType, Integer defaultNumberOfRepayments, AmortizationMethod amortizationMethod,
BigDecimal inArrearsTolerance) {
return new LoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal,
defaultNominalInterestRatePerPeriod, defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod,
interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery,
repaymentFrequencyType, defaultNumberOfRepayments, defaultMinNumberOfRepayments, defaultMaxNumberOfRepayments,
amortizationMethod, inArrearsTolerance);
return new LoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType,
defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType,
defaultNumberOfRepayments, amortizationMethod, inArrearsTolerance);
}
}