From d92a2b1f25bff50ccb8b26588836e88b3eb6f75c Mon Sep 17 00:00:00 2001 From: Keith Woodlock Date: Tue, 29 May 2012 17:36:28 +0100 Subject: [PATCH] tidy up calculate loan schedule validation. --- .../command/CalculateLoanScheduleCommand.java | 175 +++---- .../command/SubmitLoanApplicationCommand.java | 471 ++++++++++-------- .../global-translations/messages.properties | 23 +- .../WEB-INF/views/newloanapplication.jsp | 54 +- .../webapp/WEB-INF/views/view-templates.jsp | 30 +- .../platform/ImportPlatformServiceImpl.java | 79 +-- .../platform/api/LoansApiResource.java | 64 +-- .../LoanRepaymentScheduleInstallment.java | 2 +- ...CalculateLoanScheduleCommandValidator.java | 199 +------- .../CalculationPlatformServiceImpl.java | 27 +- .../platform/loan/service/LoanAssembler.java | 112 +++++ .../service/LoanWritePlatformService.java | 2 + ...WritePlatformServiceJpaRepositoryImpl.java | 70 +-- ...SubmitLoanApplicationCommandValidator.java | 32 +- .../loanschedule/domain/PmtCalculator.java | 2 - .../service/RoleReadPlatformServiceImpl.java | 1 - 16 files changed, 622 insertions(+), 721 deletions(-) create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanAssembler.java diff --git a/mifosng-data/src/main/java/org/mifosng/data/command/CalculateLoanScheduleCommand.java b/mifosng-data/src/main/java/org/mifosng/data/command/CalculateLoanScheduleCommand.java index 6d22c7a67..9b4c78f7e 100644 --- a/mifosng-data/src/main/java/org/mifosng/data/command/CalculateLoanScheduleCommand.java +++ b/mifosng-data/src/main/java/org/mifosng/data/command/CalculateLoanScheduleCommand.java @@ -10,23 +10,23 @@ import org.joda.time.LocalDate; public class CalculateLoanScheduleCommand { private String currencyCode; - private Integer digitsAfterDecimal; - private BigDecimal principal; - private BigDecimal inArrearsToleranceAmount; + private Integer digitsAfterDecimalValue; + private BigDecimal principalValue; + private BigDecimal inArrearsToleranceValue; - private Integer repaymentEvery; - private Integer repaymentFrequency; - private Integer numberOfRepayments; + private Integer repaymentEveryValue; + private Integer repaymentFrequencyType; + private Integer numberOfRepaymentsValue; - private BigDecimal interestRatePerPeriod; - private Integer interestRateFrequencyMethod; - private Integer amortizationMethod; - private Integer interestMethod; - private Integer interestCalculationPeriodMethod; + private BigDecimal interestRatePerPeriodValue; + private Integer interestRateFrequencyType; + private Integer amortizationType; + private Integer interestType; + private Integer interestCalculationPeriodType; - private LocalDate expectedDisbursementDate; - private LocalDate repaymentsStartingFromDate; - private LocalDate interestCalculatedFromDate; + private LocalDate expectedDisbursementLocalDate; + private LocalDate repaymentsStartingFromLocalDate; + private LocalDate interestChargedFromLocalDate; protected CalculateLoanScheduleCommand() { // @@ -40,20 +40,24 @@ public class CalculateLoanScheduleCommand { final LocalDate repaymentsStartingFromDate, final LocalDate interestCalculatedFromDate) { this.currencyCode = currencyCode; - this.digitsAfterDecimal = digitsAfterDecimal; - this.principal = BigDecimal.valueOf(principal.doubleValue()); - this.interestRatePerPeriod = BigDecimal.valueOf(interestRatePerPeriod.doubleValue()); - this.interestRateFrequencyMethod = interestRateFrequencyMethod; - this.interestMethod = interestMethod; - this.interestCalculationPeriodMethod = interestCalculationPeriodMethod; - this.repaymentEvery = repaymentEvery; - this.repaymentFrequency = repaymentFrequency; - this.numberOfRepayments = numberOfRepayments; - this.amortizationMethod = amortizationMethod; + this.digitsAfterDecimalValue = digitsAfterDecimal; + if (principal != null) { + this.principalValue = BigDecimal.valueOf(principal.doubleValue()); + } + if (interestRatePerPeriod != null) { + this.interestRatePerPeriodValue = BigDecimal.valueOf(interestRatePerPeriod.doubleValue()); + } + this.interestRateFrequencyType = interestRateFrequencyMethod; + this.interestType = interestMethod; + this.interestCalculationPeriodType = interestCalculationPeriodMethod; + this.repaymentEveryValue = repaymentEvery; + this.repaymentFrequencyType = repaymentFrequency; + this.numberOfRepaymentsValue = numberOfRepayments; + this.amortizationType = amortizationMethod; - this.expectedDisbursementDate = expectedDisbursementDate; - this.repaymentsStartingFromDate = repaymentsStartingFromDate; - this.interestCalculatedFromDate = interestCalculatedFromDate; + this.expectedDisbursementLocalDate = expectedDisbursementDate; + this.repaymentsStartingFromLocalDate = repaymentsStartingFromDate; + this.interestChargedFromLocalDate= interestCalculatedFromDate; } public String getCurrencyCode() { @@ -64,116 +68,119 @@ public class CalculateLoanScheduleCommand { this.currencyCode = currencyCode; } - public Integer getDigitsAfterDecimal() { - return digitsAfterDecimal; + public Integer getDigitsAfterDecimalValue() { + return digitsAfterDecimalValue; } - public void setDigitsAfterDecimal(Integer digitsAfterDecimal) { - this.digitsAfterDecimal = digitsAfterDecimal; + public void setDigitsAfterDecimalValue(Integer digitsAfterDecimalValue) { + this.digitsAfterDecimalValue = digitsAfterDecimalValue; } - public BigDecimal getPrincipal() { - return principal; + public BigDecimal getPrincipalValue() { + return principalValue; } - public void setPrincipal(BigDecimal principal) { - this.principal = principal; + public void setPrincipalValue(BigDecimal principalValue) { + this.principalValue = principalValue; } - public BigDecimal getInArrearsToleranceAmount() { - return inArrearsToleranceAmount; + public BigDecimal getInArrearsToleranceValue() { + return inArrearsToleranceValue; } - public void setInArrearsToleranceAmount(BigDecimal inArrearsToleranceAmount) { - this.inArrearsToleranceAmount = inArrearsToleranceAmount; + public void setInArrearsToleranceValue(BigDecimal inArrearsToleranceValue) { + this.inArrearsToleranceValue = inArrearsToleranceValue; } - public Integer getRepaymentEvery() { - return repaymentEvery; + public Integer getRepaymentEveryValue() { + return repaymentEveryValue; } - public void setRepaymentEvery(Integer repaymentEvery) { - this.repaymentEvery = repaymentEvery; + public void setRepaymentEveryValue(Integer repaymentEveryValue) { + this.repaymentEveryValue = repaymentEveryValue; } - public Integer getRepaymentFrequency() { - return repaymentFrequency; + public Integer getRepaymentFrequencyType() { + return repaymentFrequencyType; } - public void setRepaymentFrequency(Integer repaymentFrequency) { - this.repaymentFrequency = repaymentFrequency; + public void setRepaymentFrequencyType(Integer repaymentFrequencyType) { + this.repaymentFrequencyType = repaymentFrequencyType; } - public Integer getNumberOfRepayments() { - return numberOfRepayments; + public Integer getNumberOfRepaymentsValue() { + return numberOfRepaymentsValue; } - public void setNumberOfRepayments(Integer numberOfRepayments) { - this.numberOfRepayments = numberOfRepayments; + public void setNumberOfRepaymentsValue(Integer numberOfRepaymentsValue) { + this.numberOfRepaymentsValue = numberOfRepaymentsValue; } - public BigDecimal getInterestRatePerPeriod() { - return interestRatePerPeriod; + public BigDecimal getInterestRatePerPeriodValue() { + return interestRatePerPeriodValue; } - public void setInterestRatePerPeriod(BigDecimal interestRatePerPeriod) { - this.interestRatePerPeriod = interestRatePerPeriod; + public void setInterestRatePerPeriodValue(BigDecimal interestRatePerPeriodValue) { + this.interestRatePerPeriodValue = interestRatePerPeriodValue; } - public Integer getInterestRateFrequencyMethod() { - return interestRateFrequencyMethod; + public Integer getInterestRateFrequencyType() { + return interestRateFrequencyType; } - public void setInterestRateFrequencyMethod(Integer interestRateFrequencyMethod) { - this.interestRateFrequencyMethod = interestRateFrequencyMethod; + public void setInterestRateFrequencyType(Integer interestRateFrequencyType) { + this.interestRateFrequencyType = interestRateFrequencyType; } - public Integer getAmortizationMethod() { - return amortizationMethod; + public Integer getAmortizationType() { + return amortizationType; } - public void setAmortizationMethod(Integer amortizationMethod) { - this.amortizationMethod = amortizationMethod; + public void setAmortizationType(Integer amortizationType) { + this.amortizationType = amortizationType; } - public Integer getInterestMethod() { - return interestMethod; + public Integer getInterestType() { + return interestType; } - public void setInterestMethod(Integer interestMethod) { - this.interestMethod = interestMethod; + public void setInterestType(Integer interestType) { + this.interestType = interestType; } - public Integer getInterestCalculationPeriodMethod() { - return interestCalculationPeriodMethod; + public Integer getInterestCalculationPeriodType() { + return interestCalculationPeriodType; } - public void setInterestCalculationPeriodMethod( - Integer interestCalculationPeriodMethod) { - this.interestCalculationPeriodMethod = interestCalculationPeriodMethod; + public void setInterestCalculationPeriodType( + Integer interestCalculationPeriodType) { + this.interestCalculationPeriodType = interestCalculationPeriodType; } - public LocalDate getExpectedDisbursementDate() { - return expectedDisbursementDate; + public LocalDate getExpectedDisbursementLocalDate() { + return expectedDisbursementLocalDate; } - public void setExpectedDisbursementDate(LocalDate expectedDisbursementDate) { - this.expectedDisbursementDate = expectedDisbursementDate; + public void setExpectedDisbursementLocalDate( + LocalDate expectedDisbursementLocalDate) { + this.expectedDisbursementLocalDate = expectedDisbursementLocalDate; } - public LocalDate getRepaymentsStartingFromDate() { - return repaymentsStartingFromDate; + public LocalDate getRepaymentsStartingFromLocalDate() { + return repaymentsStartingFromLocalDate; } - public void setRepaymentsStartingFromDate(LocalDate repaymentsStartingFromDate) { - this.repaymentsStartingFromDate = repaymentsStartingFromDate; + public void setRepaymentsStartingFromLocalDate( + LocalDate repaymentsStartingFromLocalDate) { + this.repaymentsStartingFromLocalDate = repaymentsStartingFromLocalDate; } - public LocalDate getInterestCalculatedFromDate() { - return interestCalculatedFromDate; + public LocalDate getInterestChargedFromLocalDate() { + return interestChargedFromLocalDate; } - public void setInterestCalculatedFromDate(LocalDate interestCalculatedFromDate) { - this.interestCalculatedFromDate = interestCalculatedFromDate; + public void setInterestChargedFromLocalDate( + LocalDate interestChargedFromLocalDate) { + this.interestChargedFromLocalDate = interestChargedFromLocalDate; } } \ No newline at end of file diff --git a/mifosng-data/src/main/java/org/mifosng/data/command/SubmitLoanApplicationCommand.java b/mifosng-data/src/main/java/org/mifosng/data/command/SubmitLoanApplicationCommand.java index 42ac4ae2e..64205f24a 100644 --- a/mifosng-data/src/main/java/org/mifosng/data/command/SubmitLoanApplicationCommand.java +++ b/mifosng-data/src/main/java/org/mifosng/data/command/SubmitLoanApplicationCommand.java @@ -10,38 +10,44 @@ import org.mifosng.data.LoanSchedule; @XmlRootElement public class SubmitLoanApplicationCommand { - private Long applicantId; + private Long clientId; private Long productId; // product + private String locale; private String currencyCode; - private Integer digitsAfterDecimal; - private String principalFormatted; - private BigDecimal principal; - private String inArrearsToleranceAmountFormatted; - private BigDecimal inArrearsToleranceAmount; + private String digitsAfterDecimal; + private Integer digitsAfterDecimalValue; + private BigDecimal principalValue; + private String principal; + private BigDecimal inArrearsToleranceValue; + private String inArrearsTolerance; - private Integer repaymentEvery; - private Integer repaymentFrequency; - private Integer numberOfRepayments; + private String numberOfRepayments; + private Integer numberOfRepaymentsValue; + private String repaymentEvery; + private Integer repaymentEveryValue; - private String interestRatePerPeriodFormatted; - private BigDecimal interestRatePerPeriod; - private Integer interestRateFrequencyMethod; - private Integer amortizationMethod; - private Integer interestMethod; - private Integer interestCalculationPeriodMethod; + private String interestRatePerPeriod; + private BigDecimal interestRatePerPeriodValue; + + private Integer repaymentFrequencyType; + private Integer interestRateFrequencyType; + private Integer amortizationType; + private Integer interestType; + private Integer interestCalculationPeriodType; + // end of product related fields - private String expectedDisbursementDateFormatted; - private String repaymentsStartingFromDateFormatted; - private String interestCalculatedFromDateFormatted; - private LocalDate expectedDisbursementDate; - private LocalDate repaymentsStartingFromDate; - private LocalDate interestCalculatedFromDate; + private String expectedDisbursementDate; + private String repaymentsStartingFromDate; + private String interestChargedFromDate; + private LocalDate expectedDisbursementLocalDate; + private LocalDate repaymentsStartingFromLocalDate; + private LocalDate interestChargedFromLocalDate; private String dateFormat; - private String submittedOnDateFormatted; - private LocalDate submittedOnDate; + private String submittedOnDate; + private LocalDate submittedOnLocalDate; private String submittedOnNote; private String externalId; @@ -51,49 +57,42 @@ public class SubmitLoanApplicationCommand { // } - public SubmitLoanApplicationCommand(final Long applicantId, + public SubmitLoanApplicationCommand(final Long clientId, final Long productId, final LocalDate submittedOnDate, final String submittedOnNote, final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate, - final LocalDate interestCalculatedFromDate, + final LocalDate interestChargedFromLocalDate, final LoanSchedule loanSchedule, final String currencyCode, final Integer digitsAfterDecimal, final Number principal, final Number interestRatePerPeriod, Integer interestRateFrequencyMethod, final Integer interestMethod, final Integer interestCalculationPeriodMethod, final Integer repaymentEvery, final Integer repaymentFrequency, final Integer numberOfRepayments, Integer amortizationMethod, final Number toleranceAmount) { - this.applicantId = applicantId; + this.clientId = clientId; this.productId = productId; - this.submittedOnDate = submittedOnDate; + this.submittedOnLocalDate = submittedOnDate; this.submittedOnNote = submittedOnNote; - this.expectedDisbursementDate = expectedDisbursementDate; - this.repaymentsStartingFromDate = repaymentsStartingFromDate; - this.interestCalculatedFromDate = interestCalculatedFromDate; + this.expectedDisbursementLocalDate = expectedDisbursementDate; + this.repaymentsStartingFromLocalDate = repaymentsStartingFromDate; + this.interestChargedFromLocalDate = interestChargedFromLocalDate; this.loanSchedule = loanSchedule; - this.inArrearsToleranceAmount = BigDecimal.valueOf(toleranceAmount.doubleValue()); + this.inArrearsToleranceValue = BigDecimal.valueOf(toleranceAmount.doubleValue()); this.currencyCode = currencyCode; - this.digitsAfterDecimal = digitsAfterDecimal; - this.principal = BigDecimal.valueOf(principal.doubleValue()); - this.interestRatePerPeriod = BigDecimal.valueOf(interestRatePerPeriod.doubleValue()); - this.interestRateFrequencyMethod = interestRateFrequencyMethod; - this.interestMethod = interestMethod; - this.interestCalculationPeriodMethod = interestCalculationPeriodMethod; - this.repaymentEvery = repaymentEvery; - this.repaymentFrequency = repaymentFrequency; - this.numberOfRepayments = numberOfRepayments; - this.amortizationMethod = amortizationMethod; + this.digitsAfterDecimalValue = digitsAfterDecimal; + this.principalValue = BigDecimal.valueOf(principal.doubleValue()); + this.interestRatePerPeriodValue = BigDecimal.valueOf(interestRatePerPeriod.doubleValue()); + this.interestRateFrequencyType = interestRateFrequencyMethod; + this.interestType = interestMethod; + this.interestCalculationPeriodType = interestCalculationPeriodMethod; + this.repaymentEveryValue = repaymentEvery; + this.repaymentFrequencyType = repaymentFrequency; + this.numberOfRepaymentsValue = numberOfRepayments; + this.amortizationType = amortizationMethod; } public CalculateLoanScheduleCommand toCalculateLoanScheduleCommand() { - return new CalculateLoanScheduleCommand(currencyCode, digitsAfterDecimal, principal, interestRatePerPeriod, interestRateFrequencyMethod, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod, expectedDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate); - } - - public Long getApplicantId() { - return this.applicantId; - } - - public void setApplicantId(final Long applicantId) { - this.applicantId = applicantId; + return new CalculateLoanScheduleCommand(currencyCode, digitsAfterDecimalValue, principalValue, interestRatePerPeriodValue, interestRateFrequencyType, interestType, interestCalculationPeriodType, repaymentEveryValue, repaymentFrequencyType, numberOfRepaymentsValue, amortizationType, + expectedDisbursementLocalDate, repaymentsStartingFromLocalDate, interestChargedFromLocalDate); } public Long getProductId() { @@ -104,14 +103,6 @@ public class SubmitLoanApplicationCommand { this.productId = productId; } - public LocalDate getSubmittedOnDate() { - return this.submittedOnDate; - } - - public void setSubmittedOnDate(final LocalDate submittedOnDate) { - this.submittedOnDate = submittedOnDate; - } - public String getSubmittedOnNote() { return this.submittedOnNote; } @@ -120,24 +111,6 @@ public class SubmitLoanApplicationCommand { this.submittedOnNote = submittedOnNote; } - public LocalDate getExpectedDisbursementDate() { - return this.expectedDisbursementDate; - } - - public void setExpectedDisbursementDate( - final LocalDate expectedDisbursementDate) { - this.expectedDisbursementDate = expectedDisbursementDate; - } - - public LocalDate getRepaymentsStartingFromDate() { - return this.repaymentsStartingFromDate; - } - - public void setRepaymentsStartingFromDate( - final LocalDate repaymentsStartingFromDate) { - this.repaymentsStartingFromDate = repaymentsStartingFromDate; - } - public LoanSchedule getLoanSchedule() { return this.loanSchedule; } @@ -162,130 +135,6 @@ public class SubmitLoanApplicationCommand { this.currencyCode = currencyCode; } - public Integer getDigitsAfterDecimal() { - return digitsAfterDecimal; - } - - public void setDigitsAfterDecimal(Integer digitsAfterDecimal) { - this.digitsAfterDecimal = digitsAfterDecimal; - } - - public BigDecimal getPrincipal() { - return principal; - } - - public void setPrincipal(BigDecimal principal) { - this.principal = principal; - } - - public BigDecimal getInArrearsToleranceAmount() { - return inArrearsToleranceAmount; - } - - public void setInArrearsToleranceAmount(BigDecimal inArrearsToleranceAmount) { - this.inArrearsToleranceAmount = inArrearsToleranceAmount; - } - - public Integer getRepaymentEvery() { - return repaymentEvery; - } - - public void setRepaymentEvery(Integer repaymentEvery) { - this.repaymentEvery = repaymentEvery; - } - - public Integer getRepaymentFrequency() { - return repaymentFrequency; - } - - public void setRepaymentFrequency(Integer repaymentFrequency) { - this.repaymentFrequency = repaymentFrequency; - } - - public Integer getNumberOfRepayments() { - return numberOfRepayments; - } - - public void setNumberOfRepayments(Integer numberOfRepayments) { - this.numberOfRepayments = numberOfRepayments; - } - - public BigDecimal getInterestRatePerPeriod() { - return interestRatePerPeriod; - } - - public void setInterestRatePerPeriod(BigDecimal interestRatePerPeriod) { - this.interestRatePerPeriod = interestRatePerPeriod; - } - - public Integer getInterestRateFrequencyMethod() { - return interestRateFrequencyMethod; - } - - public void setInterestRateFrequencyMethod(Integer interestRateFrequencyMethod) { - this.interestRateFrequencyMethod = interestRateFrequencyMethod; - } - - public Integer getAmortizationMethod() { - return amortizationMethod; - } - - public void setAmortizationMethod(Integer amortizationMethod) { - this.amortizationMethod = amortizationMethod; - } - - public Integer getInterestMethod() { - return interestMethod; - } - - public void setInterestMethod(Integer interestMethod) { - this.interestMethod = interestMethod; - } - - public Integer getInterestCalculationPeriodMethod() { - return interestCalculationPeriodMethod; - } - - public void setInterestCalculationPeriodMethod( - Integer interestCalculationPeriodMethod) { - this.interestCalculationPeriodMethod = interestCalculationPeriodMethod; - } - - public LocalDate getInterestCalculatedFromDate() { - return interestCalculatedFromDate; - } - - public void setInterestCalculatedFromDate(LocalDate interestCalculatedFromDate) { - this.interestCalculatedFromDate = interestCalculatedFromDate; - } - - public String getExpectedDisbursementDateFormatted() { - return expectedDisbursementDateFormatted; - } - - public void setExpectedDisbursementDateFormatted( - String expectedDisbursementDateFormatted) { - this.expectedDisbursementDateFormatted = expectedDisbursementDateFormatted; - } - - public String getRepaymentsStartingFromDateFormatted() { - return repaymentsStartingFromDateFormatted; - } - - public void setRepaymentsStartingFromDateFormatted( - String repaymentsStartingFromDateFormatted) { - this.repaymentsStartingFromDateFormatted = repaymentsStartingFromDateFormatted; - } - - public String getInterestCalculatedFromDateFormatted() { - return interestCalculatedFromDateFormatted; - } - - public void setInterestCalculatedFromDateFormatted( - String interestCalculatedFromDateFormatted) { - this.interestCalculatedFromDateFormatted = interestCalculatedFromDateFormatted; - } - public String getDateFormat() { return dateFormat; } @@ -294,37 +143,223 @@ public class SubmitLoanApplicationCommand { this.dateFormat = dateFormat; } - public String getSubmittedOnDateFormatted() { - return submittedOnDateFormatted; + public Long getClientId() { + return clientId; } - public void setSubmittedOnDateFormatted(String submittedOnDateFormatted) { - this.submittedOnDateFormatted = submittedOnDateFormatted; + public void setClientId(Long clientId) { + this.clientId = clientId; } - public String getPrincipalFormatted() { - return principalFormatted; + public String getLocale() { + return locale; } - public void setPrincipalFormatted(String principalFormatted) { - this.principalFormatted = principalFormatted; + public void setLocale(String locale) { + this.locale = locale; } - public String getInArrearsToleranceAmountFormatted() { - return inArrearsToleranceAmountFormatted; + public String getDigitsAfterDecimal() { + return digitsAfterDecimal; } - public void setInArrearsToleranceAmountFormatted( - String inArrearsToleranceAmountFormatted) { - this.inArrearsToleranceAmountFormatted = inArrearsToleranceAmountFormatted; + public void setDigitsAfterDecimal(String digitsAfterDecimal) { + this.digitsAfterDecimal = digitsAfterDecimal; } - public String getInterestRatePerPeriodFormatted() { - return interestRatePerPeriodFormatted; + public Integer getDigitsAfterDecimalValue() { + return digitsAfterDecimalValue; } - public void setInterestRatePerPeriodFormatted( - String interestRatePerPeriodFormatted) { - this.interestRatePerPeriodFormatted = interestRatePerPeriodFormatted; + public void setDigitsAfterDecimalValue(Integer digitsAfterDecimalValue) { + this.digitsAfterDecimalValue = digitsAfterDecimalValue; + } + + public BigDecimal getPrincipalValue() { + return principalValue; + } + + public void setPrincipalValue(BigDecimal principalValue) { + this.principalValue = principalValue; + } + + public String getPrincipal() { + return principal; + } + + public void setPrincipal(String principal) { + this.principal = principal; + } + + public BigDecimal getInArrearsToleranceValue() { + return inArrearsToleranceValue; + } + + public void setInArrearsToleranceValue(BigDecimal inArrearsToleranceValue) { + this.inArrearsToleranceValue = inArrearsToleranceValue; + } + + public String getInArrearsTolerance() { + return inArrearsTolerance; + } + + public void setInArrearsTolerance(String inArrearsTolerance) { + this.inArrearsTolerance = inArrearsTolerance; + } + + public String getNumberOfRepayments() { + return numberOfRepayments; + } + + public void setNumberOfRepayments(String numberOfRepayments) { + this.numberOfRepayments = numberOfRepayments; + } + + public Integer getNumberOfRepaymentsValue() { + return numberOfRepaymentsValue; + } + + public void setNumberOfRepaymentsValue(Integer numberOfRepaymentsValue) { + this.numberOfRepaymentsValue = numberOfRepaymentsValue; + } + + public String getRepaymentEvery() { + return repaymentEvery; + } + + public void setRepaymentEvery(String repaymentEvery) { + this.repaymentEvery = repaymentEvery; + } + + public Integer getRepaymentEveryValue() { + return repaymentEveryValue; + } + + public void setRepaymentEveryValue(Integer repaymentEveryValue) { + this.repaymentEveryValue = repaymentEveryValue; + } + + public String getInterestRatePerPeriod() { + return interestRatePerPeriod; + } + + public void setInterestRatePerPeriod(String interestRatePerPeriod) { + this.interestRatePerPeriod = interestRatePerPeriod; + } + + public BigDecimal getInterestRatePerPeriodValue() { + return interestRatePerPeriodValue; + } + + public void setInterestRatePerPeriodValue(BigDecimal interestRatePerPeriodValue) { + this.interestRatePerPeriodValue = interestRatePerPeriodValue; + } + + public Integer getRepaymentFrequencyType() { + return repaymentFrequencyType; + } + + public void setRepaymentFrequencyType(Integer repaymentFrequencyType) { + this.repaymentFrequencyType = repaymentFrequencyType; + } + + public Integer getInterestRateFrequencyType() { + return interestRateFrequencyType; + } + + public void setInterestRateFrequencyType(Integer interestRateFrequencyType) { + this.interestRateFrequencyType = interestRateFrequencyType; + } + + public Integer getAmortizationType() { + return amortizationType; + } + + public void setAmortizationType(Integer amortizationType) { + this.amortizationType = amortizationType; + } + + public Integer getInterestType() { + return interestType; + } + + public void setInterestType(Integer interestType) { + this.interestType = interestType; + } + + public Integer getInterestCalculationPeriodType() { + return interestCalculationPeriodType; + } + + public void setInterestCalculationPeriodType( + Integer interestCalculationPeriodType) { + this.interestCalculationPeriodType = interestCalculationPeriodType; + } + + public String getExpectedDisbursementDate() { + return expectedDisbursementDate; + } + + public void setExpectedDisbursementDate(String expectedDisbursementDate) { + this.expectedDisbursementDate = expectedDisbursementDate; + } + + public String getRepaymentsStartingFromDate() { + return repaymentsStartingFromDate; + } + + public void setRepaymentsStartingFromDate(String repaymentsStartingFromDate) { + this.repaymentsStartingFromDate = repaymentsStartingFromDate; + } + + public LocalDate getExpectedDisbursementLocalDate() { + return expectedDisbursementLocalDate; + } + + public void setExpectedDisbursementLocalDate( + LocalDate expectedDisbursementLocalDate) { + this.expectedDisbursementLocalDate = expectedDisbursementLocalDate; + } + + public LocalDate getRepaymentsStartingFromLocalDate() { + return repaymentsStartingFromLocalDate; + } + + public void setRepaymentsStartingFromLocalDate( + LocalDate repaymentsStartingFromLocalDate) { + this.repaymentsStartingFromLocalDate = repaymentsStartingFromLocalDate; + } + + public LocalDate getInterestChargedFromLocalDate() { + return interestChargedFromLocalDate; + } + + public void setInterestChargedFromLocalDate( + LocalDate interestChargedFromLocalDate) { + this.interestChargedFromLocalDate = interestChargedFromLocalDate; + } + + public String getSubmittedOnDate() { + return submittedOnDate; + } + + public void setSubmittedOnDate(String submittedOnDate) { + this.submittedOnDate = submittedOnDate; + } + + public LocalDate getSubmittedOnLocalDate() { + return submittedOnLocalDate; + } + + public void setSubmittedOnLocalDate(LocalDate submittedOnLocalDate) { + this.submittedOnLocalDate = submittedOnLocalDate; + } + + public String getInterestChargedFromDate() { + return interestChargedFromDate; + } + + public void setInterestChargedFromDate(String interestChargedFromDate) { + this.interestChargedFromDate = interestChargedFromDate; } } \ No newline at end of file diff --git a/mifosng-individual-lending-app/src/main/webapp/WEB-INF/static/global-translations/messages.properties b/mifosng-individual-lending-app/src/main/webapp/WEB-INF/static/global-translations/messages.properties index 686ed5e96..36ebd25f0 100644 --- a/mifosng-individual-lending-app/src/main/webapp/WEB-INF/static/global-translations/messages.properties +++ b/mifosng-individual-lending-app/src/main/webapp/WEB-INF/static/global-translations/messages.properties @@ -109,10 +109,6 @@ validation.msg.loan.transaction.id.is.invalid=Loan transaction identifier is inv validation.msg.loan.state.transition.date.cannot.be.blank=A date must be provided when transitioning the loan into this state. validation.msg.note.exceeds.max.length=The content of the note exceeds max length of 1000 characters. -validation.msg.loan.repayment.date.cannot.be.blank=The repayment date cannot be blank. -validation.msg.loan.repayment.must.be.greater.than.zero=The repayment amount must be a number greater than zero. -validation.msg.loan.adjustment.must.be.zero.or.greater=The repayment amount must be a number greater than or equal to zero. - # loan event and transactions screens label.loan.on=On: label.loan.action.note=Note: @@ -128,7 +124,6 @@ dialog.title.waive.loan=Waive outstanding amount label.loan.transaction.on=Repayment on: label.loan.transaction.amount=Amount: - tab.client.account.loan.details=Details tab.client.account.loan.schedule=Schedule tab.client.account.loan.repayments=Repayments @@ -211,7 +206,23 @@ form.label.loan.interest.charged.from=Interest charged from: form.label.loan.expected.disbursement.date.on=Expected disbursement on: form.label.loan.first.repayment.on=First repayment on: -validation.msg.loan.expectedDisbursementDate.method.cannot.be.blank=Expected disbursement on field cannot be blank. +validation.msg.loan.digitsAfterDecimal.cannot.be.blank=You must enter a number to represent number of digits after decimal to be supported for product. +validation.msg.loan.digitsAfterDecimal.is.not.within.expected.range=Decimal places must be a number between {1} and {2} inclusive. +validation.msg.loan.repaymentEvery.cannot.be.blank=Repaid every cannot be blank. +validation.msg.loan.repaymentEvery.not.greater.than.zero=Repaid every must be greater than 0. +validation.msg.loan.numberOfRepayments.cannot.be.blank=# of repayments cannot be blank. +validation.msg.loan.numberOfRepayments.not.greater.than.zero=# of repayments must be greater than 0. +validation.msg.loan.principal.cannot.be.blank=Loan amount cannot be blank. +validation.msg.loan.inArrearsTolerance.cannot.be.blank=Arrears tolerance cannot be blank. +validation.msg.loan.interestRatePerPeriod.cannot.be.blank=Nominal interest rate % cannot be blank. +validation.msg.loan.principal.not.greater.than.zero=Loan amount must be greater than zero. +validation.msg.loan.inArrearsTolerance.not.zero.or.greater=Arrears tolerance must be greater than or equal to zero. +validation.msg.loan.interest.rate.per.period.amount.cannot.be.negative=Nominal interest rate % cannot be negative. +validation.msg.loan.repayment.date.cannot.be.blank=The repayment date cannot be blank. +validation.msg.loan.repayment.must.be.greater.than.zero=The repayment amount must be a number greater than zero. +validation.msg.loan.adjustment.must.be.zero.or.greater=The repayment amount must be a number greater than or equal to zero. + +validation.msg.loan.expectedDisbursementDate.cannot.be.blank=Expected disbursement on field cannot be blank. validation.msg.loan.expectedDisbursementDate.cannot.be.after.first.repayment.date=Expected disbursement date cannot be after the first repayment date. validation.msg.loan.interestCalculatedFromDate.must.be.entered.when.using.repayments.startfrom.field=The date interest is to be calculated from cannot be left blank when a date is provided for when repayments start from. validation.msg.loan.submitted.on.date.cannot.be.blank=Submitted on date cannot be blank. diff --git a/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/newloanapplication.jsp b/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/newloanapplication.jsp index 8ab0642f7..9d9eb75ff 100644 --- a/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/newloanapplication.jsp +++ b/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/newloanapplication.jsp @@ -55,9 +55,28 @@ $(document).ready(function() { return false; } }, - globalDate: function(localDateAsISOString) { + globalDate: function(dateParts) { try { - if (localDateAsISOString === null) return ""; + + if (dateParts === null || dateParts === '') return ""; + + var year = dateParts[0]; + var month = parseInt(dateParts[1]) - 1; // month is zero indexed + var day = dateParts[2]; + + var d = new Date(); + d.setFullYear(year,month,day); + + return Globalize.format(d,"dd MMMM yyyy"); + } catch(e) { + return "??"; + } + }, + globalDateAsISOString: function(localDateAsISOString) { + + try { + if (localDateAsISOString === null || localDateAsISOString === '') return ""; + var dateParts = localDateAsISOString.split("-") var year = dateParts[0]; var month = parseInt(dateParts[1]) - 1; // month is zero indexed @@ -177,13 +196,13 @@ $(document).ready(function() { }; function calculateAnnualPercentageRate() { - var periodInterestRate = parseFloat($('#interestRatePerPeriodFormatted').val()); + var periodInterestRate = parseFloat($('#interestRatePerPeriod').val()); if (isNaN(periodInterestRate)) { periodInterestRate = 0; } var periodsInYear = 12; - var periodType = $('#interestRateFrequencyMethod').val(); + var periodType = $('#interestRateFrequencyType').val(); if (periodType == 3) { periodsInYear = 1; } else if (periodType == 2) { @@ -207,7 +226,6 @@ $(document).ready(function() { dataType: 'json', cache: false, beforeSend: function(xhr) { - console.log("base64: " + base64); xhr.setRequestHeader("Authorization", "Basic " + base64); }, success: function(data, textStatus, jqXHR) { @@ -228,7 +246,7 @@ $(document).ready(function() { calculateLoanSchedule(); // change detection - $('#principalFormatted').change(function() { + $('#principal').change(function() { calculateLoanSchedule(); }); @@ -236,7 +254,7 @@ $(document).ready(function() { calculateLoanSchedule(); }); - $('#repaymentFrequency').change(function() { + $('#repaymentFrequencyType').change(function() { calculateLoanSchedule(); }); @@ -244,37 +262,37 @@ $(document).ready(function() { calculateLoanSchedule(); }); - $('#expectedDisbursementDateFormatted').change(function() { + $('#expectedDisbursementDate').change(function() { calculateLoanSchedule(); }); - $('#repaymentsStartingFromDateFormatted').change(function() { + $('#repaymentsStartingFromDate').change(function() { calculateLoanSchedule(); }); - $('#interestRatePerPeriodFormatted').change(function() { + $('#interestRatePerPeriod').change(function() { calculateAnnualPercentageRate(); calculateLoanSchedule(); }); - $('#interestRateFrequencyMethod').change(function() { + $('#interestRateFrequencyType').change(function() { calculateAnnualPercentageRate(); calculateLoanSchedule(); }); - $('#amortizationMethod').change(function() { + $('#amortizationType').change(function() { calculateLoanSchedule(); }); - $('#interestMethod').change(function() { + $('#interestType').change(function() { calculateLoanSchedule(); }); - $('#interestCalculationPeriodMethod').change(function() { + $('#interestCalculationPeriodType').change(function() { calculateLoanSchedule(); }); - $('#interestCalculatedFromDateFormatted').change(function() { + $('#interestChargedFromDate').change(function() { calculateLoanSchedule(); }); @@ -302,7 +320,6 @@ $(document).ready(function() { var calculateLoanScheduleurl = baseApiUrl + 'loans?command=calculateLoanSchedule'; var newFormData = JSON.stringify($('#entityform').serializeObject()); - console.log(newFormData); var jqxhr2 = $.ajax({ url: calculateLoanScheduleurl, @@ -312,7 +329,6 @@ $(document).ready(function() { data: newFormData, cache: false, beforeSend: function(xhr) { - console.log("base64: " + base64); xhr.setRequestHeader("Authorization", "Basic " + base64); }, success: function(data, textStatus, jqXHR) { @@ -332,7 +348,6 @@ $(document).ready(function() { var submitLoanApplicationUrl = baseApiUrl + 'loans'; var newFormData = JSON.stringify($('#entityform').serializeObject()); - console.log(newFormData); var jqxhr2 = $.ajax({ url: submitLoanApplicationUrl, @@ -342,11 +357,9 @@ $(document).ready(function() { data: newFormData, cache: false, beforeSend: function(xhr) { - console.log("base64: " + base64); xhr.setRequestHeader("Authorization", "Basic " + base64); }, beforeSend: function(xhr) { - console.log("base64: " + base64); xhr.setRequestHeader("Authorization", "Basic " + base64); }, success: function(data, textStatus, jqXHR) { @@ -368,7 +381,6 @@ $(document).ready(function() { dataType: 'json', cache: false, beforeSend: function(xhr) { - console.log("base64: " + base64); xhr.setRequestHeader("Authorization", "Basic " + base64); }, success: function(data, textStatus, jqXHR) { diff --git a/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/view-templates.jsp b/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/view-templates.jsp index de37ba7ea..0bbc92bb5 100644 --- a/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/view-templates.jsp +++ b/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/view-templates.jsp @@ -29,7 +29,7 @@ {{#each scheduledLoanInstallments}} {{=$ctx.number(installmentNumber)}} - {{=$ctx.globalDate(periodEnd)}} + {{=$ctx.globalDateAsISOString(periodEnd)}} {{=$ctx.money(principalDue)}} {{=$ctx.money(interestDue)}} {{=$ctx.money(totalInstallmentDue)}} @@ -54,7 +54,7 @@
- + @@ -84,8 +84,8 @@   - - + + @@ -103,7 +103,7 @@ - + @@ -112,7 +112,7 @@ - {{#each selectedProduct.repaymentFrequencyOptions}} {{#if $ctx.number($parent.parent.data.selectedProduct.repaymentPeriodFrequency)===$ctx.number(id)}} @@ -132,13 +132,13 @@ - + - + @@ -149,9 +149,9 @@ - + - {{#each selectedProduct.interestFrequencyOptions}} {{#if $ctx.number($parent.parent.data.selectedProduct.interestRatePeriod)===$ctx.number(id)}} @@ -171,7 +171,7 @@ - {{#each selectedProduct.possibleAmortizationOptions}} {{#if $ctx.number($parent.parent.data.selectedProduct.amortizationMethod)===$ctx.number(id)}} @@ -185,7 +185,7 @@ - {{#each selectedProduct.possibleInterestOptions}} {{#if $ctx.number($parent.parent.data.selectedProduct.interestMethod)===$ctx.number(id)}} @@ -199,7 +199,7 @@ - {{#each selectedProduct.possibleInterestRateCalculatedInPeriodOptions}} {{#if $ctx.number($parent.parent.data.selectedProduct.interestRateCalculatedInPeriod)===$ctx.number(id)}} @@ -213,13 +213,13 @@ - + - + diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/ImportPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/ImportPlatformServiceImpl.java index 9295d8bd0..82d60038b 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/ImportPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/ImportPlatformServiceImpl.java @@ -19,8 +19,6 @@ import org.joda.time.LocalDate; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; import org.mifosng.data.LoanSchedule; -import org.mifosng.data.MoneyData; -import org.mifosng.data.ScheduledLoanInstallment; import org.mifosng.data.command.CalculateLoanScheduleCommand; import org.mifosng.data.command.ImportLoanCommand; import org.mifosng.data.command.ImportLoanRepaymentsCommand; @@ -32,25 +30,21 @@ import org.mifosng.platform.api.commands.ClientCommand; import org.mifosng.platform.api.commands.ImportClientCommand; import org.mifosng.platform.client.domain.Client; import org.mifosng.platform.client.domain.ClientRepository; -import org.mifosng.platform.currency.domain.MonetaryCurrency; import org.mifosng.platform.currency.domain.Money; import org.mifosng.platform.exceptions.UnAuthenticatedUserException; -import org.mifosng.platform.loan.domain.AmortizationMethod; import org.mifosng.platform.loan.domain.DefaultLoanLifecycleStateMachine; import org.mifosng.platform.loan.domain.InterestCalculationPeriodMethod; -import org.mifosng.platform.loan.domain.InterestMethod; import org.mifosng.platform.loan.domain.Loan; import org.mifosng.platform.loan.domain.LoanLifecycleStateMachine; import org.mifosng.platform.loan.domain.LoanProduct; -import org.mifosng.platform.loan.domain.LoanProductRelatedDetail; import org.mifosng.platform.loan.domain.LoanProductRepository; -import org.mifosng.platform.loan.domain.LoanRepaymentScheduleInstallment; import org.mifosng.platform.loan.domain.LoanRepository; import org.mifosng.platform.loan.domain.LoanStatus; import org.mifosng.platform.loan.domain.LoanStatusRepository; import org.mifosng.platform.loan.domain.LoanTransaction; import org.mifosng.platform.loan.domain.PeriodFrequencyType; import org.mifosng.platform.loan.service.CalculationPlatformService; +import org.mifosng.platform.loan.service.LoanAssembler; import org.mifosng.platform.organisation.domain.Office; import org.mifosng.platform.organisation.domain.OfficeRepository; import org.mifosng.platform.organisation.domain.Organisation; @@ -75,11 +69,13 @@ public class ImportPlatformServiceImpl implements ImportPlatformService { private final CalculationPlatformService calculationPlatformService; private final LoanRepository loanRepository; private final LoanStatusRepository loanStatusRepository; + private final LoanAssembler loanAssembler; @Autowired - public ImportPlatformServiceImpl( + public ImportPlatformServiceImpl(final LoanAssembler loanAssembler, final OfficeRepository officeRepository, final ClientRepository clientRepository, final LoanProductRepository loanProductRepository, final CalculationPlatformService calculationPlatformService, final LoanRepository loanRepository, final LoanStatusRepository loanStatusRepository) { + this.loanAssembler = loanAssembler; this.officeRepository = officeRepository; this.clientRepository = clientRepository; this.loanProductRepository = loanProductRepository; @@ -138,75 +134,10 @@ public class ImportPlatformServiceImpl implements ImportPlatformService { SubmitLoanApplicationCommand command = combinedCommand.getSubmitLoanApplicationCommand(); - // most of this code can be extracted out into an Assembler - LoanProduct loanProduct = this.loanProductRepository.findOne(command - .getProductId()); - Client client = this.clientRepository.findOne(command.getApplicantId()); - - MonetaryCurrency currency = new MonetaryCurrency(command.getCurrencyCode(), command.getDigitsAfterDecimal()); - - final BigDecimal defaultNominalInterestRatePerPeriod = BigDecimal.valueOf(command - .getInterestRatePerPeriod().doubleValue()); - final PeriodFrequencyType interestPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyMethod()); - - // apr calculator - BigDecimal defaultAnnualNominalInterestRate = BigDecimal.ZERO; - switch (interestPeriodFrequencyType) { - case DAYS: - break; - case WEEKS: - defaultAnnualNominalInterestRate = command.getInterestRatePerPeriod().multiply(BigDecimal.valueOf(52)); - break; - case MONTHS: - defaultAnnualNominalInterestRate = command.getInterestRatePerPeriod().multiply(BigDecimal.valueOf(12)); - break; - case YEARS: - defaultAnnualNominalInterestRate = command.getInterestRatePerPeriod(); - break; - case INVALID: - break; - } - - final InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestMethod()); - final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command.getInterestCalculationPeriodMethod()); - - final Integer repayEvery = command.getRepaymentEvery(); - final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType - .fromInt(command.getRepaymentFrequency()); - final Integer defaultNumberOfInstallments = command.getNumberOfRepayments(); - final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationMethod()); - - LoanProductRelatedDetail loanRepaymentScheduleDetail = new LoanProductRelatedDetail(currency, command.getPrincipal(), - defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, - repayEvery, repaymentFrequencyType, defaultNumberOfInstallments, amortizationMethod, command.getInArrearsToleranceAmount()); - - LoanSchedule loanSchedule = command.getLoanSchedule(); - List loanRepaymentSchedule = loanSchedule - .getScheduledLoanInstallments(); - - Loan loan = Loan.createNew(currentUser.getOrganisation(), loanProduct, client, loanRepaymentScheduleDetail); - loan.setExternalId(command.getExternalId()); - - for (ScheduledLoanInstallment scheduledLoanInstallment : loanRepaymentSchedule) { - - MoneyData readPrincipalDue = scheduledLoanInstallment - .getPrincipalDue(); - - MoneyData readInterestDue = scheduledLoanInstallment - .getInterestDue(); - - LoanRepaymentScheduleInstallment installment = new LoanRepaymentScheduleInstallment( - loan, scheduledLoanInstallment.getInstallmentNumber(), - scheduledLoanInstallment.getPeriodStart(), - scheduledLoanInstallment.getPeriodEnd(), readPrincipalDue.getAmount(), - readInterestDue.getAmount()); - loan.addRepaymentScheduleInstallment(installment); - } + Loan loan = loanAssembler.assembleFrom(command, currentUser.getOrganisation()); LoanLifecycleStateMachine loanLifecycleStateMachine = defaultLoanLifecycleStateMachine(); - loan.submitApplication(command.getSubmittedOnDate(), command.getExpectedDisbursementDate(), command.getRepaymentsStartingFromDate(), command.getInterestCalculatedFromDate(), loanLifecycleStateMachine); - LoanStateTransitionCommand approveLoanCommand = combinedCommand.getApproveLoanCommand(); if (approveLoanCommand != null) { loan.approve(approveLoanCommand.getEventDate(), loanLifecycleStateMachine); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/LoansApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/LoansApiResource.java index 92118ef3d..a3c47976f 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/LoansApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/LoansApiResource.java @@ -109,42 +109,42 @@ public class LoansApiResource { @QueryParam("command") final String commandParam, final SubmitLoanApplicationCommand command) { - LocalDate expectedDisbursementDate = apiDataConversionService - .convertFrom(command.getExpectedDisbursementDateFormatted(), - "expectedDisbursementDateFormatted", + LocalDate expectedDisbursementLocalDate = apiDataConversionService + .convertFrom(command.getExpectedDisbursementDate(), + "expectedDisbursementDate", command.getDateFormat()); - LocalDate repaymentsStartingFromDate = apiDataConversionService - .convertFrom(command.getRepaymentsStartingFromDateFormatted(), - "repaymentsStartingFromDateFormatted", + LocalDate repaymentsStartingFromLocalDate = apiDataConversionService + .convertFrom(command.getRepaymentsStartingFromDate(), + "repaymentsStartingFromDate", command.getDateFormat()); - LocalDate interestCalculatedFromDate = apiDataConversionService - .convertFrom(command.getInterestCalculatedFromDateFormatted(), - "interestCalculatedFromDateFormatted", + LocalDate interestChargedFromLocalDate = apiDataConversionService + .convertFrom(command.getInterestChargedFromDate(), + "interestChargedFromDate", command.getDateFormat()); - LocalDate submittedOnDate = apiDataConversionService.convertFrom( - command.getSubmittedOnDateFormatted(), - "submittedOnDateFormatted", command.getDateFormat()); - command.setExpectedDisbursementDate(expectedDisbursementDate); - command.setRepaymentsStartingFromDate(repaymentsStartingFromDate); - command.setInterestCalculatedFromDate(interestCalculatedFromDate); - command.setSubmittedOnDate(submittedOnDate); + LocalDate submittedOnLocalDate = apiDataConversionService.convertFrom( + command.getSubmittedOnDate(), + "submittedOnDate", command.getDateFormat()); + + command.setExpectedDisbursementLocalDate(expectedDisbursementLocalDate); + command.setRepaymentsStartingFromLocalDate(repaymentsStartingFromLocalDate); + command.setInterestChargedFromLocalDate(interestChargedFromLocalDate); + command.setSubmittedOnLocalDate(submittedOnLocalDate); - // FIXME - pass in locale through query string or in 'request body' - Locale clientApplicationLocale = Locale.UK; - BigDecimal principal = this.apiDataConversionService.convertFrom( - command.getPrincipalFormatted(), "principalFormatted", - clientApplicationLocale); - BigDecimal interestRatePerPeriod = this.apiDataConversionService - .convertFrom(command.getInterestRatePerPeriodFormatted(), - "interestRatePerPeriodFormatted", - clientApplicationLocale); - BigDecimal inArrearsToleranceAmount = this.apiDataConversionService - .convertFrom(command.getInArrearsToleranceAmountFormatted(), - "inArrearsToleranceAmountFormatted", - clientApplicationLocale); - command.setPrincipal(principal); - command.setInterestRatePerPeriod(interestRatePerPeriod); - command.setInArrearsToleranceAmount(inArrearsToleranceAmount); + Locale clientApplicationLocale = this.apiDataConversionService.localeFromString(command.getLocale()); + BigDecimal principalValue = this.apiDataConversionService.convertFrom(command.getPrincipal(), "principal", clientApplicationLocale); + BigDecimal inArrearsToleranceValue = this.apiDataConversionService.convertFrom(command.getInArrearsTolerance(), "inArrearsTolerance", clientApplicationLocale); + BigDecimal interestRatePerPeriodValue = this.apiDataConversionService.convertFrom(command.getInterestRatePerPeriod(),"interestRatePerPeriod", clientApplicationLocale); + + Integer digitsAfterDecimalValue = this.apiDataConversionService.convertToInteger(command.getDigitsAfterDecimal(), "digitsAfterDecimal", clientApplicationLocale); + Integer repaymentEveryValue = this.apiDataConversionService.convertToInteger(command.getRepaymentEvery(), "repaymentEvery", clientApplicationLocale); + Integer numberOfRepaymentsValue = this.apiDataConversionService.convertToInteger(command.getNumberOfRepayments(), "numberOfRepayments", clientApplicationLocale); + + command.setPrincipalValue(principalValue); + command.setInArrearsToleranceValue(inArrearsToleranceValue); + command.setInterestRatePerPeriodValue(interestRatePerPeriodValue); + command.setDigitsAfterDecimalValue(digitsAfterDecimalValue); + command.setRepaymentEveryValue(repaymentEveryValue); + command.setNumberOfRepaymentsValue(numberOfRepaymentsValue); CalculateLoanScheduleCommand calculateLoanScheduleCommand = command .toCalculateLoanScheduleCommand(); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanRepaymentScheduleInstallment.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanRepaymentScheduleInstallment.java index 2fc3d42e7..9d05d814a 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanRepaymentScheduleInstallment.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanRepaymentScheduleInstallment.java @@ -99,7 +99,7 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableCustom dataValidationErrors = new ArrayList(); - if (StringUtils.isBlank(command.getCurrencyCode())) { - ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.currency.cannot.be.empty", "The parameter currencyCode cannot be blank.", "currencyCode"); - dataValidationErrors.add(error); - } + DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan"); - if (command.getDigitsAfterDecimal() != null) { - - if (command.getDigitsAfterDecimal() < 0 || command.getDigitsAfterDecimal() > 6) { - ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.currency.digitsAfterDecimal.must.be.between.zero.and.six.inclusive", "The parameter digitsAfterDecimal must be a value between 1 and 6.", "digitsAfterDecimal", command.getDigitsAfterDecimal(), 1, 6); - dataValidationErrors.add(error); - } - } else { - ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.currency.digitsAfterDecimal.cannot.be.empty", "The parameter digitsAfterDecimal cannot be blank.", "digitsAfterDecimal"); - dataValidationErrors.add(error); - } + baseDataValidator.reset().parameter("currencyCode").value(command.getCurrencyCode()).notBlank(); + baseDataValidator.reset().parameter("digitsAfterDecimal").value(command.getDigitsAfterDecimalValue()).notNull().inMinMaxRange(0, 6); + baseDataValidator.reset().parameter("principal").value(command.getPrincipalValue()).notNull().positiveAmount(); + baseDataValidator.reset().parameter("repaymentFrequencyType").value(command.getRepaymentFrequencyType()).notNull().inMinMaxRange(0, 3); + baseDataValidator.reset().parameter("repaymentEvery").value(command.getRepaymentEveryValue()).notNull().greaterThanZero(); + baseDataValidator.reset().parameter("numberOfRepayments").value(command.getNumberOfRepaymentsValue()).notNull().greaterThanZero(); + baseDataValidator.reset().parameter("interestRatePerPeriod").value(command.getInterestRatePerPeriodValue()).notNull(); + baseDataValidator.reset().parameter("interestRateFrequencyType").value(command.getInterestRateFrequencyType()).notNull().inMinMaxRange(0, 3); + baseDataValidator.reset().parameter("amortizationType").value(command.getAmortizationType()).notNull().inMinMaxRange(0, 1); + baseDataValidator.reset().parameter("interestType").value(command.getInterestType()).notNull().inMinMaxRange(0, 1); + baseDataValidator.reset().parameter("interestCalculationPeriodType").value(command.getInterestCalculationPeriodType()).notNull().inMinMaxRange(0, 1); - // FIXME - validate the number of digits before and after decimal provided (before is limited by database field, after is limited by number selected for product (and ultimately by the database field)) - if (command.getPrincipal() != null) { - if (command.getPrincipal().doubleValue() <= Double.valueOf("0.0")) { - ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.principal.amount.must.be.greater.than.zero", "The parameter principalMoney must be greater than zero.", "principalMoney"); - dataValidationErrors.add(error); - } - } else { - ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.principal.amount.cannot.be.empty", "The parameter principalMoney cannot be blank.", "principalMoney"); - dataValidationErrors.add(error); - } + baseDataValidator.reset().parameter("expectedDisbursementDate").value(command.getExpectedDisbursementLocalDate()).notNull(); - if (command.getRepaymentFrequency() != null) { - PeriodFrequencyType frequencyType = PeriodFrequencyType.fromInt(command.getRepaymentFrequency()); - ApiParameterError error = null; - switch (frequencyType) { - case DAYS: - error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 365); - break; - case WEEKS: - error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 52); - break; - case MONTHS: - error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 12); - break; - case YEARS: - error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 2); - break; - default: - error = ApiParameterError.parameterError("validation.msg.product.repayment.frequency.invalid", "The parameter repaymentFrequency is invalid.", "repaymentFrequency", command.getRepaymentFrequency()); - break; - } - if (error != null) { - dataValidationErrors.add(error); - } - } else { - ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.repayment.frequency.cannot.be.empty", "The parameter repaymentFrequency cannot be empty.", "repaymentFrequency"); - dataValidationErrors.add(error); - } - - if (command.getNumberOfRepayments() != null) { - if (command.getNumberOfRepayments() < 1 || command.getNumberOfRepayments() > 100) { - ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.number.of.repayments.is.out.of.range", "The parameter numberOfRepayments must between {1} and {2}.", "numberOfRepayments", command.getNumberOfRepayments(), 1, 100); - dataValidationErrors.add(error); - } - } else { - ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.number.of.repayments.cannot.be.empty", "The parameter numberOfRepayments cannot be empty.", "numberOfRepayments"); - dataValidationErrors.add(error); - } - - if (command.getAmortizationMethod() != null) { - AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationMethod()); - ApiParameterError error = null; - switch (amortizationMethod) { - case EQUAL_PRINCIPAL: - break; - case EQUAL_INSTALLMENTS: - break; - default: - error = ApiParameterError.parameterError("validation.msg.product.amortization.method.invalid", "The parameter amortizationMethod is invalid.", "amortizationMethod", command.getAmortizationMethod()); - dataValidationErrors.add(error); - break; - } - if (error != null) { - dataValidationErrors.add(error); - } - } else { - ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.amortization.method.cannot.be.empty", "The parameter amortizationMethod cannot be empty.", "amortizationMethod"); - dataValidationErrors.add(error); - } - - if (command.getExpectedDisbursementDate() == null) { - ApiParameterError error = ApiParameterError.parameterError("validation.msg.loan.expectedDisbursementDate.method.cannot.be.blank", "The parameter expectedDisbursementDate cannot be empty.", "expectedDisbursementDate"); - dataValidationErrors.add(error); - } else { - if (command.getRepaymentsStartingFromDate() != null - && command.getExpectedDisbursementDate().isAfter(command.getRepaymentsStartingFromDate())) { + if (command.getExpectedDisbursementLocalDate() != null) { + if (command.getRepaymentsStartingFromLocalDate() != null + && command.getExpectedDisbursementLocalDate().isAfter(command.getRepaymentsStartingFromLocalDate())) { ApiParameterError error = ApiParameterError.parameterError("validation.msg.loan.expectedDisbursementDate.cannot.be.after.first.repayment.date", "The parameter expectedDisbursementDate has a date which falls after the given first repayment date.", "expectedDisbursementDate", - command.getExpectedDisbursementDate(), command.getRepaymentsStartingFromDate()); + command.getExpectedDisbursementLocalDate(), command.getRepaymentsStartingFromLocalDate()); dataValidationErrors.add(error); } } - if (command.getRepaymentsStartingFromDate() != null && command.getInterestCalculatedFromDate() == null) { + if (command.getRepaymentsStartingFromLocalDate() != null && command.getInterestChargedFromLocalDate() == null) { ApiParameterError error = ApiParameterError.parameterError("validation.msg.loan.interestCalculatedFromDate.must.be.entered.when.using.repayments.startfrom.field", - "The parameter interestCalculatedFromDate cannot be empty when first repayment date is provided.", "interestCalculatedFromDate", command.getRepaymentsStartingFromDate()); + "The parameter interestCalculatedFromDate cannot be empty when first repayment date is provided.", "interestCalculatedFromDate", command.getRepaymentsStartingFromLocalDate()); dataValidationErrors.add(error); - } else if (command.getRepaymentsStartingFromDate() == null && command.getInterestCalculatedFromDate() != null) { + } else if (command.getRepaymentsStartingFromLocalDate() == null && command.getInterestChargedFromLocalDate() != null) { // validate interestCalculatedFromDate is after or on repaymentsStartingFromDate - if (command.getExpectedDisbursementDate().isAfter(command.getInterestCalculatedFromDate())) { - ApiParameterError error = ApiParameterError.parameterError("validation.msg.loan.interestCalculatedFromDate.cannot.be.before.disbursement.date", - "The parameter interestCalculatedFromDate cannot be before the date given for expected disbursement.", "interestCalculatedFromDate", command.getInterestCalculatedFromDate(), command.getExpectedDisbursementDate()); + if (command.getExpectedDisbursementLocalDate().isAfter(command.getInterestChargedFromLocalDate())) { + ApiParameterError error = ApiParameterError.parameterError("validation.msg.loan.interestChargedFromDate.cannot.be.before.disbursement.date", + "The parameter interestCalculatedFromDate cannot be before the date given for expected disbursement.", "interestChargedFromDate", command.getInterestChargedFromLocalDate(), command.getExpectedDisbursementLocalDate()); dataValidationErrors.add(error); } } - if (command.getInterestRatePerPeriod()!= null) { - if (command.getInterestRatePerPeriod().doubleValue() < Double.valueOf("0.0")) { - ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.interest.rate.per.period.amount.cannot.be.negative", - "The parameter interestRatePerPeriodFormatted cannot be less than zero.", "interestRatePerPeriodFormatted", - command.getInterestRatePerPeriod()); - dataValidationErrors.add(error); - } - } else { - ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.interest.rate.per.period.amount.cannot.be.empty", - "The parameter interestRatePerPeriodFormatted cannot be empty.", "interestRatePerPeriodFormatted", - command.getInterestRatePerPeriod()); - dataValidationErrors.add(error); - } - - // interest rate period type - if (command.getInterestRateFrequencyMethod() != null) { - PeriodFrequencyType frequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyMethod()); - ApiParameterError error = null; - switch (frequencyType) { - case DAYS: - break; - case WEEKS: - break; - case MONTHS: - break; - case YEARS: - break; - default: - error = ApiParameterError.parameterError("validation.msg.product.interest.frequency.invalid", - "The parameter interestRateFrequencyMethod cannot be empty.", "interestRateFrequencyMethod", command.getInterestRateFrequencyMethod()); - break; - } - if (error != null) { - dataValidationErrors.add(error); - } - } else { - ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.interest.frequency.cannot.be.empty", - "The parameter interestRateFrequencyMethod cannot be empty.", "interestRateFrequencyMethod"); - dataValidationErrors.add(error); - } - - if (command.getInterestMethod() != null) { - InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestMethod()); - ApiParameterError error = null; - switch (interestMethod) { - case DECLINING_BALANCE: - break; - case FLAT: - break; - default: - error = ApiParameterError.parameterError("validation.msg.product.interest.method.invalid", - "The parameter interestMethod is invalid.", "interestMethod", command.getInterestMethod()); - break; - } - if (error != null) { - dataValidationErrors.add(error); - } - } else { - ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.interest.method.cannot.be.empty", - "The parameter interestMethod cannot be empty.", "interestMethod"); - dataValidationErrors.add(error); - } - if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors); } - } - private ApiParameterError validateNumberExistsAndInRange(String errorCodePreFix, String fieldName, Integer value, int min, int max) { - ApiParameterError error = null; - if (value == null) { - error = ApiParameterError.parameterError(errorCodePreFix + ".cannot.be.empty", "The parameter " + fieldName + " cannot be blank.", fieldName); - } else { - if (value < min || value > max) { - error = ApiParameterError.parameterError(errorCodePreFix + ".outside.allowed.range", "The parameter " + fieldName + " must be between {0} and {1} inclusive.", fieldName, min, max); - } - } - return error; } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/CalculationPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/CalculationPlatformServiceImpl.java index 3234a80bc..1a5c70820 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/CalculationPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/CalculationPlatformServiceImpl.java @@ -51,20 +51,19 @@ public class CalculationPlatformServiceImpl implements CalculateLoanScheduleCommandValidator validator = new CalculateLoanScheduleCommandValidator(command); validator.validate(); - // assemble 'loan data' into 'domain' object [LoanProductRelatedDetail] - final BigDecimal principalAmount = BigDecimal.valueOf(command.getPrincipal().doubleValue()); - final BigDecimal defaultNominalInterestRatePerPeriod = BigDecimal.valueOf(command.getInterestRatePerPeriod().doubleValue()); - final PeriodFrequencyType interestPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyMethod()); - final InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestMethod()); - final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command.getInterestCalculationPeriodMethod()); - final Integer repayEvery = command.getRepaymentEvery(); - final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.fromInt(command.getRepaymentFrequency()); - final Integer defaultNumberOfInstallments = command.getNumberOfRepayments(); - final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationMethod()); + final BigDecimal principalAmount = command.getPrincipalValue(); + final BigDecimal defaultNominalInterestRatePerPeriod = command.getInterestRatePerPeriodValue(); + final PeriodFrequencyType interestPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyType()); + final InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestType()); + final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command.getInterestCalculationPeriodType()); + final Integer repayEvery = command.getRepaymentEveryValue(); + final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.fromInt(command.getRepaymentFrequencyType()); + final Integer defaultNumberOfInstallments = command.getNumberOfRepaymentsValue(); + final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationType()); final BigDecimal defaultAnnualNominalInterestRate = this.aprCalculator.calculateFrom(interestPeriodFrequencyType, defaultNominalInterestRatePerPeriod); - final MonetaryCurrency currency = new MonetaryCurrency(command.getCurrencyCode(), command.getDigitsAfterDecimal()); + final MonetaryCurrency currency = new MonetaryCurrency(command.getCurrencyCode(), command.getDigitsAfterDecimalValue()); // in arrerars tolerance isnt relevant when auto-calculating a loan schedule final BigDecimal inArrearsTolerance = BigDecimal.ZERO; @@ -78,11 +77,11 @@ public class CalculationPlatformServiceImpl implements LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(interestMethod); ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneByCode(command.getCurrencyCode()); - CurrencyData currencyData = new CurrencyData(applicationCurrency.getCode(), applicationCurrency.getName(), command.getDigitsAfterDecimal(), + CurrencyData currencyData = new CurrencyData(applicationCurrency.getCode(), applicationCurrency.getName(), command.getDigitsAfterDecimalValue(), applicationCurrency.getDisplaySymbol(), applicationCurrency.getNameCode()); - return loanScheduleGenerator.generate(loanScheduleInfo, command.getExpectedDisbursementDate(), command.getRepaymentsStartingFromDate(), - command.getInterestCalculatedFromDate(), currencyData); + return loanScheduleGenerator.generate(loanScheduleInfo, command.getExpectedDisbursementLocalDate(), command.getRepaymentsStartingFromLocalDate(), + command.getInterestChargedFromLocalDate(), currencyData); } @Override diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanAssembler.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanAssembler.java new file mode 100644 index 000000000..dd2032c1a --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanAssembler.java @@ -0,0 +1,112 @@ +package org.mifosng.platform.loan.service; + +import static org.mifosng.platform.Specifications.clientsThatMatch; +import static org.mifosng.platform.Specifications.productThatMatches; + +import java.math.BigDecimal; +import java.util.List; + +import org.mifosng.data.LoanSchedule; +import org.mifosng.data.MoneyData; +import org.mifosng.data.ScheduledLoanInstallment; +import org.mifosng.data.command.SubmitLoanApplicationCommand; +import org.mifosng.platform.client.domain.Client; +import org.mifosng.platform.client.domain.ClientRepository; +import org.mifosng.platform.currency.domain.MonetaryCurrency; +import org.mifosng.platform.exceptions.ClientNotFoundException; +import org.mifosng.platform.exceptions.LoanProductNotFoundException; +import org.mifosng.platform.loan.domain.AmortizationMethod; +import org.mifosng.platform.loan.domain.DefaultLoanLifecycleStateMachine; +import org.mifosng.platform.loan.domain.InterestCalculationPeriodMethod; +import org.mifosng.platform.loan.domain.InterestMethod; +import org.mifosng.platform.loan.domain.Loan; +import org.mifosng.platform.loan.domain.LoanLifecycleStateMachine; +import org.mifosng.platform.loan.domain.LoanProduct; +import org.mifosng.platform.loan.domain.LoanProductRelatedDetail; +import org.mifosng.platform.loan.domain.LoanProductRepository; +import org.mifosng.platform.loan.domain.LoanRepaymentScheduleInstallment; +import org.mifosng.platform.loan.domain.LoanStatus; +import org.mifosng.platform.loan.domain.LoanStatusRepository; +import org.mifosng.platform.loan.domain.PeriodFrequencyType; +import org.mifosng.platform.loanschedule.domain.AprCalculator; +import org.mifosng.platform.organisation.domain.Organisation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class LoanAssembler { + + private final LoanStatusRepository loanStatusRepository; + private final LoanProductRepository loanProductRepository; + private final ClientRepository clientRepository; + private final AprCalculator aprCalculator = new AprCalculator(); + + @Autowired + public LoanAssembler(final LoanStatusRepository loanStatusRepository, + final LoanProductRepository loanProductRepository, + final ClientRepository clientRepository) { + this.loanStatusRepository = loanStatusRepository; + this.loanProductRepository = loanProductRepository; + this.clientRepository = clientRepository; + } + + public Loan assembleFrom(SubmitLoanApplicationCommand command, Organisation organisation) { + LoanProduct loanProduct = this.loanProductRepository.findOne(productThatMatches(organisation, command.getProductId())); + if (loanProduct == null) { + throw new LoanProductNotFoundException(command.getProductId()); + } + Client client = this.clientRepository.findOne(clientsThatMatch(organisation, command.getClientId())); + if (client == null) { + throw new ClientNotFoundException(command.getClientId()); + } + + // FIXME - should probably fetch applicationCurrency with currencycode to check its validity. + MonetaryCurrency currency = new MonetaryCurrency(command.getCurrencyCode(), command.getDigitsAfterDecimalValue()); + + final BigDecimal defaultNominalInterestRatePerPeriod = command.getInterestRatePerPeriodValue(); + final PeriodFrequencyType interestPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyType()); + + BigDecimal defaultAnnualNominalInterestRate = aprCalculator.calculateFrom(interestPeriodFrequencyType, command.getInterestRatePerPeriodValue()); + + final InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestType()); + final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command.getInterestCalculationPeriodType()); + + final Integer repayEvery = command.getRepaymentEveryValue(); + final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.fromInt(command.getRepaymentFrequencyType()); + final Integer defaultNumberOfInstallments = command.getNumberOfRepaymentsValue(); + final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationType()); + + LoanProductRelatedDetail loanRepaymentScheduleDetail = new LoanProductRelatedDetail(currency, + command.getPrincipalValue(), defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, defaultAnnualNominalInterestRate, + interestMethod, interestCalculationPeriodMethod, + repayEvery, repaymentFrequencyType, defaultNumberOfInstallments, amortizationMethod, command.getInArrearsToleranceValue()); + + LoanSchedule loanSchedule = command.getLoanSchedule(); + List loanRepaymentSchedule = loanSchedule.getScheduledLoanInstallments(); + + Loan loan = Loan.createNew(organisation, loanProduct, client, loanRepaymentScheduleDetail); + loan.setExternalId(command.getExternalId()); + + for (ScheduledLoanInstallment scheduledLoanInstallment : loanRepaymentSchedule) { + + MoneyData readPrincipalDue = scheduledLoanInstallment.getPrincipalDue(); + MoneyData readInterestDue = scheduledLoanInstallment.getInterestDue(); + + LoanRepaymentScheduleInstallment installment = new LoanRepaymentScheduleInstallment( + loan, scheduledLoanInstallment.getInstallmentNumber(), + scheduledLoanInstallment.getPeriodStart(), + scheduledLoanInstallment.getPeriodEnd(), readPrincipalDue.getAmount(), + readInterestDue.getAmount()); + loan.addRepaymentScheduleInstallment(installment); + } + + loan.submitApplication(command.getSubmittedOnLocalDate(), command.getExpectedDisbursementLocalDate(), command.getRepaymentsStartingFromLocalDate(), command.getInterestChargedFromLocalDate(), defaultLoanLifecycleStateMachine()); + + return loan; + } + + private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() { + List allowedLoanStatuses = this.loanStatusRepository.findAll(); + return new DefaultLoanLifecycleStateMachine(allowedLoanStatuses); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformService.java index a96b4db97..a0225dfbb 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformService.java @@ -37,7 +37,9 @@ public interface LoanWritePlatformService { @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE', 'CAN_MAKE_LOAN_REPAYMENT_ROLE', 'CAN_MAKE_LOAN_REPAYMENT_IN_THE_PAST_ROLE')") public EntityIdentifier makeLoanRepayment(LoanTransactionCommand command); + @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')") EntityIdentifier adjustLoanTransaction(AdjustLoanTransactionCommand command); + @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')") EntityIdentifier waiveLoanAmount(LoanTransactionCommand command); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformServiceJpaRepositoryImpl.java index 1ce07dd82..86bc30181 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -2,7 +2,6 @@ package org.mifosng.platform.loan.service; import static org.mifosng.platform.Specifications.loansThatMatch; -import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; @@ -10,7 +9,6 @@ import org.apache.commons.lang.StringUtils; import org.joda.time.LocalDate; import org.mifosng.data.EntityIdentifier; import org.mifosng.data.LoanSchedule; -import org.mifosng.data.MoneyData; import org.mifosng.data.ScheduledLoanInstallment; import org.mifosng.data.command.AdjustLoanTransactionCommand; import org.mifosng.data.command.CalculateLoanScheduleCommand; @@ -18,8 +16,6 @@ import org.mifosng.data.command.LoanStateTransitionCommand; import org.mifosng.data.command.LoanTransactionCommand; import org.mifosng.data.command.SubmitLoanApplicationCommand; import org.mifosng.data.command.UndoStateTransitionCommand; -import org.mifosng.platform.client.domain.Client; -import org.mifosng.platform.client.domain.ClientRepository; import org.mifosng.platform.client.domain.Note; import org.mifosng.platform.client.domain.NoteRepository; import org.mifosng.platform.currency.domain.MonetaryCurrency; @@ -27,15 +23,9 @@ import org.mifosng.platform.currency.domain.Money; import org.mifosng.platform.exceptions.LoanNotFoundException; import org.mifosng.platform.exceptions.NoAuthorizationException; import org.mifosng.platform.exceptions.PlatformDomainRuleException; -import org.mifosng.platform.loan.domain.AmortizationMethod; import org.mifosng.platform.loan.domain.DefaultLoanLifecycleStateMachine; -import org.mifosng.platform.loan.domain.InterestCalculationPeriodMethod; -import org.mifosng.platform.loan.domain.InterestMethod; import org.mifosng.platform.loan.domain.Loan; import org.mifosng.platform.loan.domain.LoanLifecycleStateMachine; -import org.mifosng.platform.loan.domain.LoanProduct; -import org.mifosng.platform.loan.domain.LoanProductRelatedDetail; -import org.mifosng.platform.loan.domain.LoanProductRepository; import org.mifosng.platform.loan.domain.LoanRepaymentScheduleInstallment; import org.mifosng.platform.loan.domain.LoanRepository; import org.mifosng.platform.loan.domain.LoanStatus; @@ -43,7 +33,6 @@ import org.mifosng.platform.loan.domain.LoanStatusRepository; import org.mifosng.platform.loan.domain.LoanTransaction; import org.mifosng.platform.loan.domain.LoanTransactionRepository; import org.mifosng.platform.loan.domain.PeriodFrequencyType; -import org.mifosng.platform.loanschedule.domain.AprCalculator; import org.mifosng.platform.security.PlatformSecurityContext; import org.mifosng.platform.user.domain.AppUser; import org.springframework.beans.factory.annotation.Autowired; @@ -56,24 +45,21 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf private final PlatformSecurityContext context; private final LoanRepository loanRepository; - private final LoanProductRepository loanProductRepository; private final LoanStatusRepository loanStatusRepository; - private final ClientRepository clientRepository; private final NoteRepository noteRepository; private final CalculationPlatformService calculationPlatformService; - private final AprCalculator aprCalculator = new AprCalculator(); private final LoanTransactionRepository loanTransactionRepository; + private final LoanAssembler loanAssembler; @Autowired - public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, + public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final LoanAssembler loanAssembler, final LoanRepository loanRepository, final LoanTransactionRepository loanTransactionRepository, - final LoanStatusRepository loanStatusRepository, final LoanProductRepository loanProductRepository, - final ClientRepository clientRepository, final NoteRepository noteRepository, final CalculationPlatformService calculationPlatformService) { + final LoanStatusRepository loanStatusRepository, + final NoteRepository noteRepository, final CalculationPlatformService calculationPlatformService) { this.context = context; + this.loanAssembler = loanAssembler; this.loanRepository = loanRepository; this.loanTransactionRepository = loanTransactionRepository; - this.loanProductRepository = loanProductRepository; - this.clientRepository = clientRepository; this.loanStatusRepository = loanStatusRepository; this.noteRepository = noteRepository; this.calculationPlatformService = calculationPlatformService; @@ -97,55 +83,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf SubmitLoanApplicationCommandValidator validator = new SubmitLoanApplicationCommandValidator(command); validator.validate(); - LocalDate submittedOn = command.getSubmittedOnDate(); + LocalDate submittedOn = command.getSubmittedOnLocalDate(); if (this.isBeforeToday(submittedOn) && currentUser.hasNotPermissionForAnyOf("CAN_SUBMIT_HISTORIC_LOAN_APPLICATION_ROLE", "PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE")) { throw new NoAuthorizationException("Cannot add backdated loan."); } - // FIXME - looks like assembly of LoanProductRelatedDetail is common with loan product and calculate loan schedule areas. remove duplication into an assembler. - LoanProduct loanProduct = this.loanProductRepository.findOne(command.getProductId()); - Client client = this.clientRepository.findOne(command.getApplicantId()); + Loan loan = loanAssembler.assembleFrom(command, currentUser.getOrganisation()); - MonetaryCurrency currency = new MonetaryCurrency(command.getCurrencyCode(), command.getDigitsAfterDecimal()); - - final BigDecimal defaultNominalInterestRatePerPeriod = BigDecimal.valueOf(command.getInterestRatePerPeriod().doubleValue()); - final PeriodFrequencyType interestPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyMethod()); - - BigDecimal defaultAnnualNominalInterestRate = aprCalculator.calculateFrom(interestPeriodFrequencyType, command.getInterestRatePerPeriod()); - - final InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestMethod()); - final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command.getInterestCalculationPeriodMethod()); - - final Integer repayEvery = command.getRepaymentEvery(); - final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.fromInt(command.getRepaymentFrequency()); - final Integer defaultNumberOfInstallments = command.getNumberOfRepayments(); - final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationMethod()); - - LoanProductRelatedDetail loanRepaymentScheduleDetail = new LoanProductRelatedDetail(currency, - command.getPrincipal(), defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, defaultAnnualNominalInterestRate, - interestMethod, interestCalculationPeriodMethod, - repayEvery, repaymentFrequencyType, defaultNumberOfInstallments, amortizationMethod, command.getInArrearsToleranceAmount()); - - LoanSchedule loanSchedule = command.getLoanSchedule(); - List loanRepaymentSchedule = loanSchedule.getScheduledLoanInstallments(); - - Loan loan = Loan.createNew(currentUser.getOrganisation(), loanProduct, client, loanRepaymentScheduleDetail); - loan.setExternalId(command.getExternalId()); - - for (ScheduledLoanInstallment scheduledLoanInstallment : loanRepaymentSchedule) { - - MoneyData readPrincipalDue = scheduledLoanInstallment.getPrincipalDue(); - MoneyData readInterestDue = scheduledLoanInstallment.getInterestDue(); - - LoanRepaymentScheduleInstallment installment = new LoanRepaymentScheduleInstallment( - loan, scheduledLoanInstallment.getInstallmentNumber(), - scheduledLoanInstallment.getPeriodStart(), - scheduledLoanInstallment.getPeriodEnd(), readPrincipalDue.getAmount(), - readInterestDue.getAmount()); - loan.addRepaymentScheduleInstallment(installment); - } - - loan.submitApplication(submittedOn, command.getExpectedDisbursementDate(), command.getRepaymentsStartingFromDate(), command.getInterestCalculatedFromDate(), defaultLoanLifecycleStateMachine()); this.loanRepository.save(loan); if (StringUtils.isNotBlank(command.getSubmittedOnNote())) { diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/SubmitLoanApplicationCommandValidator.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/SubmitLoanApplicationCommandValidator.java index 7162519c7..a72aa1046 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/SubmitLoanApplicationCommandValidator.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/SubmitLoanApplicationCommandValidator.java @@ -25,15 +25,15 @@ public class SubmitLoanApplicationCommandValidator { dataValidationErrors.add(error); } - if (command.getSubmittedOnDate() == null) { + if (command.getSubmittedOnLocalDate() == null) { ApiParameterError error = ApiParameterError.parameterError("validation.msg.loan.submitted.on.date.cannot.be.blank", - "The parameter submittedOnDateFormatted cannot be empty.", "submittedOnDateFormatted"); + "The parameter submittedOnDate cannot be empty.", "submittedOnDateFormatted"); dataValidationErrors.add(error); } else { - if (command.getSubmittedOnDate().isAfter(command.getExpectedDisbursementDate())) { + if (command.getSubmittedOnLocalDate().isAfter(command.getExpectedDisbursementLocalDate())) { ApiParameterError error = ApiParameterError.parameterError("validation.msg.loan.submitted.on.date.cannot.be.after.expectedDisbursementDate", - "The date of parameter submittedOnDateFormatted cannot fall after the date given for expectedDisbursementDateFormatted.", "submittedOnDateFormatted", - command.getSubmittedOnDateFormatted(), command.getExpectedDisbursementDateFormatted()); + "The date of parameter submittedOnDate cannot fall after the date given for expectedDisbursementDate.", "submittedOnDate", + command.getSubmittedOnDate(), command.getExpectedDisbursementDate()); dataValidationErrors.add(error); } } @@ -41,17 +41,17 @@ public class SubmitLoanApplicationCommandValidator { try { // reuse calculate loan schedule validator for now CalculateLoanScheduleCommand calculateLoanScheduleCommand = new CalculateLoanScheduleCommand( - command.getCurrencyCode(), command.getDigitsAfterDecimal(), - command.getPrincipal(), command.getInterestRatePerPeriod(), - command.getInterestRateFrequencyMethod(), - command.getInterestMethod(), command.getInterestCalculationPeriodMethod(), - command.getRepaymentEvery(), - command.getRepaymentFrequency(), - command.getNumberOfRepayments(), - command.getAmortizationMethod(), - command.getExpectedDisbursementDate(), - command.getRepaymentsStartingFromDate(), - command.getInterestCalculatedFromDate()); + command.getCurrencyCode(), command.getDigitsAfterDecimalValue(), + command.getPrincipalValue(), command.getInterestRatePerPeriodValue(), + command.getInterestRateFrequencyType(), + command.getInterestType(), command.getInterestCalculationPeriodType(), + command.getRepaymentEveryValue(), + command.getRepaymentFrequencyType(), + command.getNumberOfRepaymentsValue(), + command.getAmortizationType(), + command.getExpectedDisbursementLocalDate(), + command.getRepaymentsStartingFromLocalDate(), + command.getInterestChargedFromLocalDate()); CalculateLoanScheduleCommandValidator validator = new CalculateLoanScheduleCommandValidator( calculateLoanScheduleCommand); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loanschedule/domain/PmtCalculator.java b/mifosng-provider/src/main/java/org/mifosng/platform/loanschedule/domain/PmtCalculator.java index c80e1cf69..a2aa47976 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loanschedule/domain/PmtCalculator.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loanschedule/domain/PmtCalculator.java @@ -9,7 +9,6 @@ import org.mifosng.platform.loan.domain.LoanProductRelatedDetail; public class PmtCalculator { public Money calculatePaymentForOnePeriodFrom(LoanProductRelatedDetail loanScheduleInfo, BigDecimal periodInterestRateForRepaymentPeriod, MonetaryCurrency monetaryCurrency) { - // TODO - check if going to doubles is a problem double interestRateFraction = periodInterestRateForRepaymentPeriod.doubleValue(); double futureValue = 0; @@ -24,7 +23,6 @@ public class PmtCalculator { } public Money calculateTotalRepaymentFrom(LoanProductRelatedDetail loanScheduleInfo, BigDecimal periodInterestRateForRepaymentPeriod, MonetaryCurrency monetaryCurrency) { - // TODO - check if going to doubles is a problem double interestRateFraction = periodInterestRateForRepaymentPeriod.doubleValue(); double futureValue = 0; diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/user/service/RoleReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/user/service/RoleReadPlatformServiceImpl.java index b109e8639..a8637acb8 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/user/service/RoleReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/user/service/RoleReadPlatformServiceImpl.java @@ -44,7 +44,6 @@ public class RoleReadPlatformServiceImpl implements RoleReadPlatformService { return this.jdbcTemplate.query(sql, mapper, new Object[] {currentUser.getOrganisation().getId() }); } - // FIXME - does it make sense to use JDBC over repository for this? @Override public RoleData retrieveRole(final Long id) { AppUser currentUser = context.authenticatedUser();