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; return this.client;
} }
public LoanProduct loanProduct(){
return this.loanProduct;
}
public LoanProductRelatedDetail repaymentScheduleDetail() { public LoanProductRelatedDetail repaymentScheduleDetail() {
return this.loanRepaymentScheduleDetail; return this.loanRepaymentScheduleDetail;
} }
@@ -1318,12 +1322,8 @@ public class Loan extends AbstractPersistable<Long> {
final LoanScheduleGenerator loanScheduleGenerator = new DefaultLoanScheduleGeneratorFactory().create(interestMethod); final LoanScheduleGenerator loanScheduleGenerator = new DefaultLoanScheduleGeneratorFactory().create(interestMethod);
final BigDecimal principal = this.loanRepaymentScheduleDetail.getPrincipal().getAmount(); 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 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();
@@ -1332,18 +1332,15 @@ 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, interestRatePerPeriod,
maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestRatePeriodFrequencyType, interestRatePeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod,
defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentEvery, repaymentPeriodFrequencyType, numberOfRepayments, amortizationMethod, loanTermFrequency,
repaymentPeriodFrequencyType, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, amortizationMethod, loanTermPeriodFrequencyType, setOfLoanCharges(), this.getDisbursementDate(), this.getExpectedFirstRepaymentOnDate(),
loanTermFrequency, loanTermPeriodFrequencyType, setOfLoanCharges(), this.getDisbursementDate(), this.getInterestChargedFromDate(), inArrearsTolerance);
this.getExpectedFirstRepaymentOnDate(), this.getInterestChargedFromDate(), inArrearsTolerance);
final LoanScheduleData generatedData = loanSchedule.generate(); final LoanScheduleData generatedData = loanSchedule.generate();
@@ -27,11 +27,7 @@ public final class LoanSchedule {
private final LoanScheduleGenerator loanScheduleGenerator; private final LoanScheduleGenerator loanScheduleGenerator;
private final ApplicationCurrency applicationCurrency; private final ApplicationCurrency applicationCurrency;
private final BigDecimal principal; private final BigDecimal principal;
private final BigDecimal minPrincipal;
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;
@@ -39,8 +35,6 @@ 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;
@@ -52,22 +46,17 @@ public final class LoanSchedule {
private final Set<LoanCharge> loanCharges; private final Set<LoanCharge> loanCharges;
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 nominalInterestRatePerPeriod,
final BigDecimal nominalInterestRatePerPeriod, final BigDecimal minNominalInterestRatePerPeriod, final BigDecimal maxNominalInterestRatePerPeriod, final PeriodFrequencyType interestRatePeriodFrequencyType, final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal nominalAnnualInterestRate,
final BigDecimal nominalAnnualInterestRate, final InterestMethod interestMethod, final InterestMethod interestMethod, final InterestCalculationPeriodMethod interestCalculationPeriodMethod,
final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Integer repaymentEvery, 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) {
this.loanScheduleGenerator = loanScheduleGenerator; this.loanScheduleGenerator = loanScheduleGenerator;
this.applicationCurrency = applicationCurrency; this.applicationCurrency = applicationCurrency;
this.principal = principal; this.principal = principal;
this.minPrincipal = minPrincipal;
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;
@@ -75,8 +64,6 @@ 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;
@@ -95,9 +82,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, minNominalInterestRatePerPeriod, maxNominalInterestRatePerPeriod, return LoanProductRelatedDetail.createFrom(currency, principal, nominalInterestRatePerPeriod, interestRatePeriodFrequencyType,
interestRatePeriodFrequencyType, nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod, nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentPeriodFrequencyType,
repaymentEvery, repaymentPeriodFrequencyType, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, amortizationMethod, this.inArrearsTolerance); numberOfRepayments, amortizationMethod, this.inArrearsTolerance);
} }
public Integer getLoanTermFrequency() { public Integer getLoanTermFrequency() {
@@ -73,33 +73,7 @@ public class LoanScheduleAssembler {
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency); final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
final BigDecimal principal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element); 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 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",
@@ -116,18 +90,6 @@ 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);
@@ -144,10 +106,10 @@ 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, interestRatePerPeriod,
minInterestRatePerPeriod, maxInterestRatePerPeriod, interestRatePeriodFrequencyType, defaultAnnualNominalInterestRate, interestRatePeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod,
interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentPeriodFrequencyType, numberOfRepayments, amortizationMethod, loanTermFrequency,
minNumberOfRepayments, maxNumberOfRepayments, amortizationMethod, loanTermFrequency, loanTermPeriodFrequencyType, loanTermPeriodFrequencyType, loanCharges, expectedDisbursementDate, repaymentsStartingFromDate, interestChargedFromDate,
loanCharges, expectedDisbursementDate, repaymentsStartingFromDate, interestChargedFromDate, inArrearsTolerance); inArrearsTolerance);
} }
} }
@@ -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.LoanProduct; import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.mifosplatform.portfolio.loanproduct.serialization.LoanProductCommandFromApiJsonDeserializer;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -50,12 +51,15 @@ public final class LoanApplicationCommandFromApiJsonHelper {
private final FromJsonHelper fromApiJsonHelper; private final FromJsonHelper fromApiJsonHelper;
private final LoanProductCommandFromApiJsonDeserializer loanProductCommandFromApiJsonDeserializer;
@Autowired @Autowired
public LoanApplicationCommandFromApiJsonHelper(final FromJsonHelper fromApiJsonHelper) { public LoanApplicationCommandFromApiJsonHelper(final FromJsonHelper fromApiJsonHelper, final LoanProductCommandFromApiJsonDeserializer loanProductCommandFromApiJsonDeserializer) {
this.fromApiJsonHelper = fromApiJsonHelper; 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(); } if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType(); 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", if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); } "Validation errors exist.", dataValidationErrors); }
} }
@@ -593,19 +599,11 @@ public final class LoanApplicationCommandFromApiJsonHelper {
"Validation errors exist.", dataValidationErrors); } "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 List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan"); final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
this.loanProductCommandFromApiJsonDeserializer.validateMinMaxConstraints(element, baseDataValidator, loanProduct);
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);
}
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); } "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.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;
@@ -93,7 +92,6 @@ 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,
@@ -105,8 +103,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
final LoanProductRepository loanProductRepository, final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, final LoanProductRepository loanProductRepository, 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) {
final LoanProductCommandFromApiJsonDeserializer loanProductCommandFromApiJsonDeserializer) {
this.context = context; this.context = context;
this.fromJsonHelper = fromJsonHelper; this.fromJsonHelper = fromJsonHelper;
this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator; this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator;
@@ -125,7 +122,6 @@ 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() {
@@ -139,8 +135,12 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
AppUser currentUser = context.authenticatedUser(); 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 //validate dates against calendar recurring dates
//get calendar //get calendar
@@ -203,7 +203,6 @@ 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); }
@@ -233,6 +232,9 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
existingLoanApplication.updateLoanProduct(loanProduct); existingLoanApplication.updateLoanProduct(loanProduct);
} }
//validate min and maximum constraints
this.fromApiJsonDeserializer.validateMinMaxConstraintsForModification(command.json(), existingLoanApplication.loanProduct());
final String fundIdParamName = "fundId"; final String fundIdParamName = "fundId";
if (changes.containsKey(fundIdParamName)) { if (changes.containsKey(fundIdParamName)) {
final Long fundId = command.longValueOfParameterNamed(fundIdParamName); final Long fundId = command.longValueOfParameterNamed(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.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 +68,6 @@ 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 LoanProductCommandFromApiJsonDeserializer loanProductCommandFromApiJsonDeserializer;
@Autowired @Autowired
public LoanAssembler(final FromJsonHelper fromApiJsonHelper, final LoanProductRepository loanProductRepository, public LoanAssembler(final FromJsonHelper fromApiJsonHelper, final LoanProductRepository loanProductRepository,
@@ -78,8 +76,7 @@ public class LoanAssembler {
final StaffRepository staffRepository, final CodeValueRepositoryWrapper codeValueRepository, final StaffRepository staffRepository, final CodeValueRepositoryWrapper codeValueRepository,
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 LoanProductCommandFromApiJsonDeserializer loanProductCommandFromApiJsonDeserializer) {
this.fromApiJsonHelper = fromApiJsonHelper; this.fromApiJsonHelper = fromApiJsonHelper;
this.loanProductRepository = loanProductRepository; this.loanProductRepository = loanProductRepository;
this.clientRepository = clientRepository; this.clientRepository = clientRepository;
@@ -93,7 +90,6 @@ public class LoanAssembler {
this.loanCollateralAssembler = loanCollateralAssembler; this.loanCollateralAssembler = loanCollateralAssembler;
this.loanSummaryWrapper = loanSummaryWrapper; this.loanSummaryWrapper = loanSummaryWrapper;
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory; this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
this.loanProductCommandFromApiJsonDeserializer = loanProductCommandFromApiJsonDeserializer;
} }
public Loan assembleFrom(final JsonCommand command, final AppUser currentUser) { public Loan assembleFrom(final JsonCommand command, final AppUser currentUser) {
@@ -117,9 +113,6 @@ public class LoanAssembler {
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId); final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
if (loanProduct == null) { throw new LoanProductNotFoundException(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 Fund fund = findFundByIdIfProvided(fundId);
final Staff loanOfficer = findLoanOfficerByIdIfProvided(loanOfficerId); final Staff loanOfficer = findLoanOfficerByIdIfProvided(loanOfficerId);
final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided(transactionProcessingStrategyId); final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided(transactionProcessingStrategyId);
@@ -66,6 +66,9 @@ public class LoanProduct extends AbstractPersistable<Long> {
@Embedded @Embedded
private final LoanProductRelatedDetail loanProductRelatedDetail; private final LoanProductRelatedDetail loanProductRelatedDetail;
@Embedded
private LoanProductMinMaxConstraints loanProductMinMaxConstraints;
@Column(name = "accounting_type", nullable = false) @Column(name = "accounting_type", nullable = false)
private Integer accountingRule; private Integer accountingRule;
@@ -110,6 +113,7 @@ public class LoanProduct extends AbstractPersistable<Long> {
protected LoanProduct() { protected LoanProduct() {
this.loanProductRelatedDetail = null; this.loanProductRelatedDetail = null;
this.loanProductMinMaxConstraints = null;
} }
public LoanProduct(final Fund fund, final LoanTransactionProcessingStrategy transactionProcessingStrategy, final String name, public LoanProduct(final Fund fund, final LoanTransactionProcessingStrategy transactionProcessingStrategy, final String name,
@@ -136,11 +140,13 @@ public class LoanProduct extends AbstractPersistable<Long> {
this.charges = charges; this.charges = charges;
} }
this.loanProductRelatedDetail = new LoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal, this.loanProductRelatedDetail = new LoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod,
defaultNominalInterestRatePerPeriod, defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod,
interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery,
repaymentFrequencyType, defaultNumberOfInstallments, defaultMinNumberOfInstallments, defaultMaxNumberOfInstallments, repaymentFrequencyType, defaultNumberOfInstallments, amortizationMethod, inArrearsTolerance);
amortizationMethod, inArrearsTolerance);
this.loanProductMinMaxConstraints = new LoanProductMinMaxConstraints(defaultMinPrincipal, defaultMaxPrincipal,
defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod, defaultMinNumberOfInstallments,
defaultMaxNumberOfInstallments);
if (accountingRuleType != null) { if (accountingRuleType != null) {
this.accountingRule = accountingRuleType.getValue(); 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) { public Map<String, Object> update(final JsonCommand command, final AprCalculator aprCalculator) {
final Map<String, Object> actualChanges = this.loanProductRelatedDetail.update(command, aprCalculator); final Map<String, Object> actualChanges = this.loanProductRelatedDetail.update(command, aprCalculator);
actualChanges.putAll(this.loanProductMinMaxConstraints().update(command));
final String accountingTypeParamName = "accountingRule"; final String accountingTypeParamName = "accountingRule";
if (command.isChangeInIntegerParameterNamed(accountingTypeParamName, this.accountingRule)) { if (command.isChangeInIntegerParameterNamed(accountingTypeParamName, this.accountingRule)) {
@@ -246,11 +253,11 @@ public class LoanProduct extends AbstractPersistable<Long> {
} }
public Money getMinPrincipalAmount(){ public Money getMinPrincipalAmount(){
return this.loanProductRelatedDetail.getMinPrincipal(); return Money.of(this.loanProductRelatedDetail.getCurrency(), this.loanProductMinMaxConstraints().getMinPrincipal());
} }
public Money getMaxPrincipalAmount(){ public Money getMaxPrincipalAmount(){
return this.loanProductRelatedDetail.getMaxPrincipal(); return Money.of(this.loanProductRelatedDetail.getCurrency(), this.loanProductMinMaxConstraints().getMaxPrincipal());
} }
public BigDecimal getNominalInterestRatePerPeriod() { public BigDecimal getNominalInterestRatePerPeriod() {
@@ -258,26 +265,34 @@ public class LoanProduct extends AbstractPersistable<Long> {
} }
public BigDecimal getMinNominalInterestRatePerPeriod() { public BigDecimal getMinNominalInterestRatePerPeriod() {
return this.loanProductRelatedDetail.getMinNominalInterestRatePerPeriod(); return this.loanProductMinMaxConstraints().getMinNominalInterestRatePerPeriod();
} }
public BigDecimal getMaxNominalInterestRatePerPeriod(){ public BigDecimal getMaxNominalInterestRatePerPeriod(){
return this.loanProductRelatedDetail.getMaxNominalInterestRatePerPeriod(); return this.loanProductMinMaxConstraints().getMaxNominalInterestRatePerPeriod();
} }
public Integer getNumberOfRepayments(){ public Integer getNumberOfRepayments(){
return this.loanProductRelatedDetail.getNumberOfRepayments(); return this.loanProductRelatedDetail().getNumberOfRepayments();
} }
public Integer getMinNumberOfRepayments() { public Integer getMinNumberOfRepayments() {
return this.loanProductRelatedDetail.getMinNumberOfRepayments(); return this.loanProductMinMaxConstraints().getMinNumberOfRepayments();
} }
public Integer getMaxNumberOfRepayments() { public Integer getMaxNumberOfRepayments() {
return this.loanProductRelatedDetail.getMaxNumberOfRepayments(); return this.loanProductMinMaxConstraints().getMaxNumberOfRepayments();
} }
public LoanProductRelatedDetail loanProductRelatedDetail(){ public LoanProductRelatedDetail loanProductRelatedDetail(){
return this.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,21 +34,9 @@ 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 = 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) @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)
@@ -82,12 +70,6 @@ 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)
@@ -98,18 +80,15 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
private BigDecimal inArrearsTolerance; private BigDecimal inArrearsTolerance;
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 nominalInterestRatePerPeriod, final PeriodFrequencyType interestRatePeriodFrequencyType,
final BigDecimal minNominalInterestRatePerPeriod, final BigDecimal maxNominalInterestRatePerPeriod, final BigDecimal nominalAnnualInterestRate, final InterestMethod interestMethod,
final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal nominalAnnualInterestRate, final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Integer repaymentEvery,
final InterestMethod interestMethod, final InterestCalculationPeriodMethod interestCalculationPeriodMethod, 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, return new LoanProductRelatedDetail(currency, principal, nominalInterestRatePerPeriod, interestRatePeriodFrequencyType,
minNominalInterestRatePerPeriod, maxNominalInterestRatePerPeriod, interestRatePeriodFrequencyType,
nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentPeriodFrequencyType, nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentPeriodFrequencyType,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, amortizationMethod, inArrearsTolerance); numberOfRepayments, amortizationMethod, inArrearsTolerance);
} }
protected LoanProductRelatedDetail() { protected LoanProductRelatedDetail() {
@@ -117,21 +96,14 @@ 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 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.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;
@@ -139,8 +111,6 @@ 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;
@@ -157,14 +127,6 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
return Money.of(this.currency, this.principal); 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() { public Money getInArrearsTolerance() {
return Money.of(this.currency, this.inArrearsTolerance); return Money.of(this.currency, this.inArrearsTolerance);
} }
@@ -173,16 +135,6 @@ 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;
} }
@@ -214,14 +166,6 @@ 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;
} }
@@ -264,22 +208,6 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
final String localeAsInput = command.locale(); 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"; final String principalParamName = "principal";
if (command.isChangeInBigDecimalParameterNamed(principalParamName, this.principal)) { if (command.isChangeInBigDecimalParameterNamed(principalParamName, this.principal)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(principalParamName); final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(principalParamName);
@@ -304,22 +232,6 @@ 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);
@@ -344,22 +256,6 @@ 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);
@@ -23,7 +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.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -261,7 +261,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
throwExceptionIfValidationWarningsExist(dataValidationErrors); throwExceptionIfValidationWarningsExist(dataValidationErrors);
} }
public void validateForUpdate(final String json) { public void validateForUpdate(final String json, final LoanProduct loanProduct) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType(); 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()) baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue())
.value(receivablePenaltyAccountId).ignoreIfNull().integerGreaterThanZero(); .value(receivablePenaltyAccountId).ignoreIfNull().integerGreaterThanZero();
throwExceptionIfValidationWarningsExist(dataValidationErrors); validateMinMaxConstraints(element, baseDataValidator, loanProduct);
}
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); throwExceptionIfValidationWarningsExist(dataValidationErrors);
} }
private void validatePrincipalMinMaxConstraint(final JsonElement element, final LoanProductRelatedDetail loanProductRelatedDetail, final DataValidatorBuilder baseDataValidator) { public void validateMinMaxConstraints(final JsonElement element, final DataValidatorBuilder baseDataValidator, final LoanProduct loanProduct){
validatePrincipalMinMaxConstraint(element, loanProduct, baseDataValidator);
validateNumberOfRepaymentsMinMaxConstraint(element, loanProduct, baseDataValidator);
validateNominalInterestRatePerPeriodMinMaxConstraint(element, loanProduct, baseDataValidator);
}
private void validatePrincipalMinMaxConstraint(final JsonElement element, final LoanProduct loanProduct, final DataValidatorBuilder baseDataValidator) {
boolean principalUpdated = false; boolean principalUpdated = false;
boolean minPrincipalUpdated = false; boolean minPrincipalUpdated = false;
@@ -472,7 +470,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
principalAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(principalParameterName, element); principalAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(principalParameterName, element);
principalUpdated = true; principalUpdated = true;
}else{ }else{
principalAmount = loanProductRelatedDetail.getPrincipal().getAmount(); principalAmount = loanProduct.getPrincipalAmount().getAmount();
} }
String minPrincipalParameterName = "minPrincipal"; String minPrincipalParameterName = "minPrincipal";
@@ -481,7 +479,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
minPrincipalAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minPrincipalParameterName, element); minPrincipalAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minPrincipalParameterName, element);
minPrincipalUpdated = true; minPrincipalUpdated = true;
}else{ }else{
minPrincipalAmount = loanProductRelatedDetail.getMinPrincipal().getAmount(); minPrincipalAmount = loanProduct.getMinPrincipalAmount().getAmount();
} }
String maxPrincipalParameterName = "maxPrincipal"; String maxPrincipalParameterName = "maxPrincipal";
@@ -490,7 +488,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
maxPrincipalAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxPrincipalParameterName, element); maxPrincipalAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxPrincipalParameterName, element);
maxPrincipalUpdated = true; maxPrincipalUpdated = true;
}else{ }else{
maxPrincipalAmount = loanProductRelatedDetail.getMaxPrincipal().getAmount(); maxPrincipalAmount = loanProduct.getMaxPrincipalAmount().getAmount();
} }
if(minPrincipalUpdated){ 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 numberOfRepaymentsUpdated = false;
boolean minNumberOfRepaymentsUpdated = false; boolean minNumberOfRepaymentsUpdated = false;
boolean maxNumberOfRepaymentsUpdated = false; boolean maxNumberOfRepaymentsUpdated = false;
@@ -526,7 +524,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed(numberOfRepaymentsParameterName, element); numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed(numberOfRepaymentsParameterName, element);
numberOfRepaymentsUpdated = true; numberOfRepaymentsUpdated = true;
}else{ }else{
numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments(); numberOfRepayments = loanProduct.getNumberOfRepayments();
} }
String minNumberOfRepaymentsParameterName = "minNumberOfRepayments"; String minNumberOfRepaymentsParameterName = "minNumberOfRepayments";
@@ -535,7 +533,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
minNumberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed(minNumberOfRepaymentsParameterName, element); minNumberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed(minNumberOfRepaymentsParameterName, element);
minNumberOfRepaymentsUpdated = true; minNumberOfRepaymentsUpdated = true;
}else{ }else{
minNumberOfRepayments = loanProductRelatedDetail.getMinNumberOfRepayments(); minNumberOfRepayments = loanProduct.getMinNumberOfRepayments();
} }
String maxNumberOfRepaymentsParameterName = "maxNumberOfRepayments"; String maxNumberOfRepaymentsParameterName = "maxNumberOfRepayments";
@@ -544,7 +542,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
maxNumberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed(maxNumberOfRepaymentsParameterName, element); maxNumberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed(maxNumberOfRepaymentsParameterName, element);
maxNumberOfRepaymentsUpdated = true; maxNumberOfRepaymentsUpdated = true;
}else{ }else{
maxNumberOfRepayments = loanProductRelatedDetail.getMaxNumberOfRepayments(); maxNumberOfRepayments = loanProduct.getMaxNumberOfRepayments();
} }
if(minNumberOfRepaymentsUpdated){ 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 iRPUpdated = false;
boolean minIRPUpdated = false; boolean minIRPUpdated = false;
@@ -580,7 +578,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(interestRatePerPeriodParameterName, element); interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(interestRatePerPeriodParameterName, element);
iRPUpdated = true; iRPUpdated = true;
}else{ }else{
interestRatePerPeriod = loanProductRelatedDetail.getNominalInterestRatePerPeriod(); interestRatePerPeriod = loanProduct.getNominalInterestRatePerPeriod();
} }
String minInterestRatePerPeriodParameterName = "minInterestRatePerPeriod"; String minInterestRatePerPeriodParameterName = "minInterestRatePerPeriod";
@@ -589,7 +587,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
minInterestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minInterestRatePerPeriodParameterName, element); minInterestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minInterestRatePerPeriodParameterName, element);
minIRPUpdated = true; minIRPUpdated = true;
}else{ }else{
minInterestRatePerPeriod = loanProductRelatedDetail.getMinNominalInterestRatePerPeriod(); minInterestRatePerPeriod = loanProduct.getMinNominalInterestRatePerPeriod();
} }
String maxInterestRatePerPeriodParameterName = "maxInterestRatePerPeriod"; String maxInterestRatePerPeriodParameterName = "maxInterestRatePerPeriod";
@@ -598,7 +596,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
maxInterestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxInterestRatePerPeriodParameterName, element); maxInterestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(maxInterestRatePerPeriodParameterName, element);
maxIRPUpdated = true; maxIRPUpdated = true;
}else{ }else{
maxInterestRatePerPeriod = loanProductRelatedDetail.getMaxNominalInterestRatePerPeriod(); maxInterestRatePerPeriod = loanProduct.getMaxNominalInterestRatePerPeriod();
} }
if(minIRPUpdated){ if(minIRPUpdated){
@@ -132,12 +132,10 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
try { try {
this.context.authenticatedUser(); this.context.authenticatedUser();
this.fromApiJsonDeserializer.validateForUpdate(command.json());
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"); this.fromApiJsonDeserializer.validateForUpdate(command.json(), product);
final Map<String, Object> changes = product.update(command, this.aprCalculator); 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(); MonetaryCurrency currency = new MonetaryCurrencyBuilder().withCode("USD").withDigitsAfterDecimal(2).build();
BigDecimal defaultPrincipal = BigDecimal.valueOf(Double.valueOf("200000")); 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 // 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"));
@@ -37,29 +33,21 @@ 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, return createLoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType,
defaultNominalInterestRatePerPeriod, defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType,
interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, defaultNumberOfRepayments, amortizationMethod, inArrearsTolerance);
repaymentFrequencyType, defaultNumberOfRepayments, defaultMinNumberOfRepayments, defaultMaxNumberOfRepayments,
amortizationMethod, inArrearsTolerance);
} }
public static LoanProductRelatedDetail createSettingsForEqualInstallmentAmortizationQuarterly() { public static LoanProductRelatedDetail createSettingsForEqualInstallmentAmortizationQuarterly() {
MonetaryCurrency currency = new MonetaryCurrencyBuilder().withCode("USD").withDigitsAfterDecimal(2).build(); MonetaryCurrency currency = new MonetaryCurrencyBuilder().withCode("USD").withDigitsAfterDecimal(2).build();
BigDecimal defaultPrincipal = BigDecimal.valueOf(Double.valueOf("200000")); 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 // 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"));
@@ -69,30 +57,22 @@ 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, return createLoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType,
defaultNominalInterestRatePerPeriod, defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType,
interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, defaultNumberOfRepayments, amortizationMethod, inArrearsTolerance);
repaymentFrequencyType, defaultNumberOfRepayments, defaultMinNumberOfRepayments, defaultMaxNumberOfRepayments,
amortizationMethod, inArrearsTolerance);
} }
public static LoanProductRelatedDetail createSettingsForFlatQuarterly(final AmortizationMethod amortizationMethod) { public static LoanProductRelatedDetail createSettingsForFlatQuarterly(final AmortizationMethod amortizationMethod) {
MonetaryCurrency currency = new MonetaryCurrencyBuilder().withCode("USD").withDigitsAfterDecimal(2).build(); MonetaryCurrency currency = new MonetaryCurrencyBuilder().withCode("USD").withDigitsAfterDecimal(2).build();
BigDecimal defaultPrincipal = BigDecimal.valueOf(Double.valueOf("200000")); 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 // 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"));
@@ -102,29 +82,21 @@ 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, return createLoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType,
defaultNominalInterestRatePerPeriod, defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType,
interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, defaultNumberOfRepayments, amortizationMethod, inArrearsTolerance);
repaymentFrequencyType, defaultNumberOfRepayments, defaultMinNumberOfRepayments, defaultMaxNumberOfRepayments,
amortizationMethod, inArrearsTolerance);
} }
public static LoanProductRelatedDetail createSettingsForIrregularFlatEveryFourMonths() { public static LoanProductRelatedDetail createSettingsForIrregularFlatEveryFourMonths() {
MonetaryCurrency currency = new MonetaryCurrencyBuilder().withCode("KSH").withDigitsAfterDecimal(0).build(); MonetaryCurrency currency = new MonetaryCurrencyBuilder().withCode("KSH").withDigitsAfterDecimal(0).build();
BigDecimal defaultPrincipal = BigDecimal.valueOf(Double.valueOf("15000")); 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 // 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"));
@@ -134,31 +106,25 @@ 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, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType,
defaultNominalInterestRatePerPeriod, defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod, interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType,
interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType, defaultNumberOfRepayments, defaultMinNumberOfRepayments, defaultMaxNumberOfRepayments, amortizationMethod, defaultNumberOfRepayments, 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 defaultNominalInterestRatePerPeriod, PeriodFrequencyType interestPeriodFrequencyType,
BigDecimal defaultMinNominalInterestRatePerPeriod, BigDecimal defaultMaxNominalInterestRatePerPeriod, BigDecimal defaultAnnualNominalInterestRate, InterestMethod interestMethod,
PeriodFrequencyType interestPeriodFrequencyType, BigDecimal defaultAnnualNominalInterestRate, InterestMethod interestMethod,
InterestCalculationPeriodMethod interestCalculationPeriodMethod, Integer repayEvery, InterestCalculationPeriodMethod interestCalculationPeriodMethod, Integer repayEvery,
PeriodFrequencyType repaymentFrequencyType, Integer defaultNumberOfRepayments, Integer defaultMinNumberOfRepayments, PeriodFrequencyType repaymentFrequencyType, Integer defaultNumberOfRepayments, AmortizationMethod amortizationMethod,
Integer defaultMaxNumberOfRepayments, AmortizationMethod amortizationMethod, BigDecimal inArrearsTolerance) { BigDecimal inArrearsTolerance) {
return new LoanProductRelatedDetail(currency, defaultPrincipal, defaultMinPrincipal, defaultMaxPrincipal, return new LoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType,
defaultNominalInterestRatePerPeriod, defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType,
interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, defaultNumberOfRepayments, amortizationMethod, inArrearsTolerance);
repaymentFrequencyType, defaultNumberOfRepayments, defaultMinNumberOfRepayments, defaultMaxNumberOfRepayments,
amortizationMethod, inArrearsTolerance);
} }
} }