tidy up calculate loan schedule validation.

This commit is contained in:
Keith Woodlock
2012-05-29 17:36:28 +01:00
parent 1450e38f7b
commit d92a2b1f25
16 changed files with 622 additions and 721 deletions
@@ -10,23 +10,23 @@ import org.joda.time.LocalDate;
public class CalculateLoanScheduleCommand { public class CalculateLoanScheduleCommand {
private String currencyCode; private String currencyCode;
private Integer digitsAfterDecimal; private Integer digitsAfterDecimalValue;
private BigDecimal principal; private BigDecimal principalValue;
private BigDecimal inArrearsToleranceAmount; private BigDecimal inArrearsToleranceValue;
private Integer repaymentEvery; private Integer repaymentEveryValue;
private Integer repaymentFrequency; private Integer repaymentFrequencyType;
private Integer numberOfRepayments; private Integer numberOfRepaymentsValue;
private BigDecimal interestRatePerPeriod; private BigDecimal interestRatePerPeriodValue;
private Integer interestRateFrequencyMethod; private Integer interestRateFrequencyType;
private Integer amortizationMethod; private Integer amortizationType;
private Integer interestMethod; private Integer interestType;
private Integer interestCalculationPeriodMethod; private Integer interestCalculationPeriodType;
private LocalDate expectedDisbursementDate; private LocalDate expectedDisbursementLocalDate;
private LocalDate repaymentsStartingFromDate; private LocalDate repaymentsStartingFromLocalDate;
private LocalDate interestCalculatedFromDate; private LocalDate interestChargedFromLocalDate;
protected CalculateLoanScheduleCommand() { protected CalculateLoanScheduleCommand() {
// //
@@ -40,20 +40,24 @@ public class CalculateLoanScheduleCommand {
final LocalDate repaymentsStartingFromDate, final LocalDate interestCalculatedFromDate) { final LocalDate repaymentsStartingFromDate, final LocalDate interestCalculatedFromDate) {
this.currencyCode = currencyCode; this.currencyCode = currencyCode;
this.digitsAfterDecimal = digitsAfterDecimal; this.digitsAfterDecimalValue = digitsAfterDecimal;
this.principal = BigDecimal.valueOf(principal.doubleValue()); if (principal != null) {
this.interestRatePerPeriod = BigDecimal.valueOf(interestRatePerPeriod.doubleValue()); this.principalValue = BigDecimal.valueOf(principal.doubleValue());
this.interestRateFrequencyMethod = interestRateFrequencyMethod; }
this.interestMethod = interestMethod; if (interestRatePerPeriod != null) {
this.interestCalculationPeriodMethod = interestCalculationPeriodMethod; this.interestRatePerPeriodValue = BigDecimal.valueOf(interestRatePerPeriod.doubleValue());
this.repaymentEvery = repaymentEvery; }
this.repaymentFrequency = repaymentFrequency; this.interestRateFrequencyType = interestRateFrequencyMethod;
this.numberOfRepayments = numberOfRepayments; this.interestType = interestMethod;
this.amortizationMethod = amortizationMethod; this.interestCalculationPeriodType = interestCalculationPeriodMethod;
this.repaymentEveryValue = repaymentEvery;
this.repaymentFrequencyType = repaymentFrequency;
this.numberOfRepaymentsValue = numberOfRepayments;
this.amortizationType = amortizationMethod;
this.expectedDisbursementDate = expectedDisbursementDate; this.expectedDisbursementLocalDate = expectedDisbursementDate;
this.repaymentsStartingFromDate = repaymentsStartingFromDate; this.repaymentsStartingFromLocalDate = repaymentsStartingFromDate;
this.interestCalculatedFromDate = interestCalculatedFromDate; this.interestChargedFromLocalDate= interestCalculatedFromDate;
} }
public String getCurrencyCode() { public String getCurrencyCode() {
@@ -64,116 +68,119 @@ public class CalculateLoanScheduleCommand {
this.currencyCode = currencyCode; this.currencyCode = currencyCode;
} }
public Integer getDigitsAfterDecimal() { public Integer getDigitsAfterDecimalValue() {
return digitsAfterDecimal; return digitsAfterDecimalValue;
} }
public void setDigitsAfterDecimal(Integer digitsAfterDecimal) { public void setDigitsAfterDecimalValue(Integer digitsAfterDecimalValue) {
this.digitsAfterDecimal = digitsAfterDecimal; this.digitsAfterDecimalValue = digitsAfterDecimalValue;
} }
public BigDecimal getPrincipal() { public BigDecimal getPrincipalValue() {
return principal; return principalValue;
} }
public void setPrincipal(BigDecimal principal) { public void setPrincipalValue(BigDecimal principalValue) {
this.principal = principal; this.principalValue = principalValue;
} }
public BigDecimal getInArrearsToleranceAmount() { public BigDecimal getInArrearsToleranceValue() {
return inArrearsToleranceAmount; return inArrearsToleranceValue;
} }
public void setInArrearsToleranceAmount(BigDecimal inArrearsToleranceAmount) { public void setInArrearsToleranceValue(BigDecimal inArrearsToleranceValue) {
this.inArrearsToleranceAmount = inArrearsToleranceAmount; this.inArrearsToleranceValue = inArrearsToleranceValue;
} }
public Integer getRepaymentEvery() { public Integer getRepaymentEveryValue() {
return repaymentEvery; return repaymentEveryValue;
} }
public void setRepaymentEvery(Integer repaymentEvery) { public void setRepaymentEveryValue(Integer repaymentEveryValue) {
this.repaymentEvery = repaymentEvery; this.repaymentEveryValue = repaymentEveryValue;
} }
public Integer getRepaymentFrequency() { public Integer getRepaymentFrequencyType() {
return repaymentFrequency; return repaymentFrequencyType;
} }
public void setRepaymentFrequency(Integer repaymentFrequency) { public void setRepaymentFrequencyType(Integer repaymentFrequencyType) {
this.repaymentFrequency = repaymentFrequency; this.repaymentFrequencyType = repaymentFrequencyType;
} }
public Integer getNumberOfRepayments() { public Integer getNumberOfRepaymentsValue() {
return numberOfRepayments; return numberOfRepaymentsValue;
} }
public void setNumberOfRepayments(Integer numberOfRepayments) { public void setNumberOfRepaymentsValue(Integer numberOfRepaymentsValue) {
this.numberOfRepayments = numberOfRepayments; this.numberOfRepaymentsValue = numberOfRepaymentsValue;
} }
public BigDecimal getInterestRatePerPeriod() { public BigDecimal getInterestRatePerPeriodValue() {
return interestRatePerPeriod; return interestRatePerPeriodValue;
} }
public void setInterestRatePerPeriod(BigDecimal interestRatePerPeriod) { public void setInterestRatePerPeriodValue(BigDecimal interestRatePerPeriodValue) {
this.interestRatePerPeriod = interestRatePerPeriod; this.interestRatePerPeriodValue = interestRatePerPeriodValue;
} }
public Integer getInterestRateFrequencyMethod() { public Integer getInterestRateFrequencyType() {
return interestRateFrequencyMethod; return interestRateFrequencyType;
} }
public void setInterestRateFrequencyMethod(Integer interestRateFrequencyMethod) { public void setInterestRateFrequencyType(Integer interestRateFrequencyType) {
this.interestRateFrequencyMethod = interestRateFrequencyMethod; this.interestRateFrequencyType = interestRateFrequencyType;
} }
public Integer getAmortizationMethod() { public Integer getAmortizationType() {
return amortizationMethod; return amortizationType;
} }
public void setAmortizationMethod(Integer amortizationMethod) { public void setAmortizationType(Integer amortizationType) {
this.amortizationMethod = amortizationMethod; this.amortizationType = amortizationType;
} }
public Integer getInterestMethod() { public Integer getInterestType() {
return interestMethod; return interestType;
} }
public void setInterestMethod(Integer interestMethod) { public void setInterestType(Integer interestType) {
this.interestMethod = interestMethod; this.interestType = interestType;
} }
public Integer getInterestCalculationPeriodMethod() { public Integer getInterestCalculationPeriodType() {
return interestCalculationPeriodMethod; return interestCalculationPeriodType;
} }
public void setInterestCalculationPeriodMethod( public void setInterestCalculationPeriodType(
Integer interestCalculationPeriodMethod) { Integer interestCalculationPeriodType) {
this.interestCalculationPeriodMethod = interestCalculationPeriodMethod; this.interestCalculationPeriodType = interestCalculationPeriodType;
} }
public LocalDate getExpectedDisbursementDate() { public LocalDate getExpectedDisbursementLocalDate() {
return expectedDisbursementDate; return expectedDisbursementLocalDate;
} }
public void setExpectedDisbursementDate(LocalDate expectedDisbursementDate) { public void setExpectedDisbursementLocalDate(
this.expectedDisbursementDate = expectedDisbursementDate; LocalDate expectedDisbursementLocalDate) {
this.expectedDisbursementLocalDate = expectedDisbursementLocalDate;
} }
public LocalDate getRepaymentsStartingFromDate() { public LocalDate getRepaymentsStartingFromLocalDate() {
return repaymentsStartingFromDate; return repaymentsStartingFromLocalDate;
} }
public void setRepaymentsStartingFromDate(LocalDate repaymentsStartingFromDate) { public void setRepaymentsStartingFromLocalDate(
this.repaymentsStartingFromDate = repaymentsStartingFromDate; LocalDate repaymentsStartingFromLocalDate) {
this.repaymentsStartingFromLocalDate = repaymentsStartingFromLocalDate;
} }
public LocalDate getInterestCalculatedFromDate() { public LocalDate getInterestChargedFromLocalDate() {
return interestCalculatedFromDate; return interestChargedFromLocalDate;
} }
public void setInterestCalculatedFromDate(LocalDate interestCalculatedFromDate) { public void setInterestChargedFromLocalDate(
this.interestCalculatedFromDate = interestCalculatedFromDate; LocalDate interestChargedFromLocalDate) {
this.interestChargedFromLocalDate = interestChargedFromLocalDate;
} }
} }
@@ -10,38 +10,44 @@ import org.mifosng.data.LoanSchedule;
@XmlRootElement @XmlRootElement
public class SubmitLoanApplicationCommand { public class SubmitLoanApplicationCommand {
private Long applicantId; private Long clientId;
private Long productId; private Long productId;
// product // product
private String locale;
private String currencyCode; private String currencyCode;
private Integer digitsAfterDecimal; private String digitsAfterDecimal;
private String principalFormatted; private Integer digitsAfterDecimalValue;
private BigDecimal principal; private BigDecimal principalValue;
private String inArrearsToleranceAmountFormatted; private String principal;
private BigDecimal inArrearsToleranceAmount; private BigDecimal inArrearsToleranceValue;
private String inArrearsTolerance;
private Integer repaymentEvery; private String numberOfRepayments;
private Integer repaymentFrequency; private Integer numberOfRepaymentsValue;
private Integer numberOfRepayments; private String repaymentEvery;
private Integer repaymentEveryValue;
private String interestRatePerPeriodFormatted; private String interestRatePerPeriod;
private BigDecimal interestRatePerPeriod; private BigDecimal interestRatePerPeriodValue;
private Integer interestRateFrequencyMethod;
private Integer amortizationMethod; private Integer repaymentFrequencyType;
private Integer interestMethod; private Integer interestRateFrequencyType;
private Integer interestCalculationPeriodMethod; private Integer amortizationType;
private Integer interestType;
private Integer interestCalculationPeriodType;
// end of product related fields
private String expectedDisbursementDateFormatted; private String expectedDisbursementDate;
private String repaymentsStartingFromDateFormatted; private String repaymentsStartingFromDate;
private String interestCalculatedFromDateFormatted; private String interestChargedFromDate;
private LocalDate expectedDisbursementDate; private LocalDate expectedDisbursementLocalDate;
private LocalDate repaymentsStartingFromDate; private LocalDate repaymentsStartingFromLocalDate;
private LocalDate interestCalculatedFromDate; private LocalDate interestChargedFromLocalDate;
private String dateFormat; private String dateFormat;
private String submittedOnDateFormatted; private String submittedOnDate;
private LocalDate submittedOnDate; private LocalDate submittedOnLocalDate;
private String submittedOnNote; private String submittedOnNote;
private String externalId; 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 Long productId, final LocalDate submittedOnDate,
final String submittedOnNote, final String submittedOnNote,
final LocalDate expectedDisbursementDate, final LocalDate expectedDisbursementDate,
final LocalDate repaymentsStartingFromDate, final LocalDate repaymentsStartingFromDate,
final LocalDate interestCalculatedFromDate, final LocalDate interestChargedFromLocalDate,
final LoanSchedule loanSchedule, final String currencyCode, final LoanSchedule loanSchedule, final String currencyCode,
final Integer digitsAfterDecimal, final Number principal, final Integer digitsAfterDecimal, final Number principal,
final Number interestRatePerPeriod, Integer interestRateFrequencyMethod, final Integer interestMethod, final Integer interestCalculationPeriodMethod, 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) { final Integer repaymentEvery, final Integer repaymentFrequency, final Integer numberOfRepayments, Integer amortizationMethod, final Number toleranceAmount) {
this.applicantId = applicantId; this.clientId = clientId;
this.productId = productId; this.productId = productId;
this.submittedOnDate = submittedOnDate; this.submittedOnLocalDate = submittedOnDate;
this.submittedOnNote = submittedOnNote; this.submittedOnNote = submittedOnNote;
this.expectedDisbursementDate = expectedDisbursementDate; this.expectedDisbursementLocalDate = expectedDisbursementDate;
this.repaymentsStartingFromDate = repaymentsStartingFromDate; this.repaymentsStartingFromLocalDate = repaymentsStartingFromDate;
this.interestCalculatedFromDate = interestCalculatedFromDate; this.interestChargedFromLocalDate = interestChargedFromLocalDate;
this.loanSchedule = loanSchedule; this.loanSchedule = loanSchedule;
this.inArrearsToleranceAmount = BigDecimal.valueOf(toleranceAmount.doubleValue()); this.inArrearsToleranceValue = BigDecimal.valueOf(toleranceAmount.doubleValue());
this.currencyCode = currencyCode; this.currencyCode = currencyCode;
this.digitsAfterDecimal = digitsAfterDecimal; this.digitsAfterDecimalValue = digitsAfterDecimal;
this.principal = BigDecimal.valueOf(principal.doubleValue()); this.principalValue = BigDecimal.valueOf(principal.doubleValue());
this.interestRatePerPeriod = BigDecimal.valueOf(interestRatePerPeriod.doubleValue()); this.interestRatePerPeriodValue = BigDecimal.valueOf(interestRatePerPeriod.doubleValue());
this.interestRateFrequencyMethod = interestRateFrequencyMethod; this.interestRateFrequencyType = interestRateFrequencyMethod;
this.interestMethod = interestMethod; this.interestType = interestMethod;
this.interestCalculationPeriodMethod = interestCalculationPeriodMethod; this.interestCalculationPeriodType = interestCalculationPeriodMethod;
this.repaymentEvery = repaymentEvery; this.repaymentEveryValue = repaymentEvery;
this.repaymentFrequency = repaymentFrequency; this.repaymentFrequencyType = repaymentFrequency;
this.numberOfRepayments = numberOfRepayments; this.numberOfRepaymentsValue = numberOfRepayments;
this.amortizationMethod = amortizationMethod; this.amortizationType = amortizationMethod;
} }
public CalculateLoanScheduleCommand toCalculateLoanScheduleCommand() { public CalculateLoanScheduleCommand toCalculateLoanScheduleCommand() {
return new CalculateLoanScheduleCommand(currencyCode, digitsAfterDecimal, principal, interestRatePerPeriod, interestRateFrequencyMethod, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentFrequency, numberOfRepayments, amortizationMethod, expectedDisbursementDate, repaymentsStartingFromDate, interestCalculatedFromDate); return new CalculateLoanScheduleCommand(currencyCode, digitsAfterDecimalValue, principalValue, interestRatePerPeriodValue, interestRateFrequencyType, interestType, interestCalculationPeriodType, repaymentEveryValue, repaymentFrequencyType, numberOfRepaymentsValue, amortizationType,
} expectedDisbursementLocalDate, repaymentsStartingFromLocalDate, interestChargedFromLocalDate);
public Long getApplicantId() {
return this.applicantId;
}
public void setApplicantId(final Long applicantId) {
this.applicantId = applicantId;
} }
public Long getProductId() { public Long getProductId() {
@@ -104,14 +103,6 @@ public class SubmitLoanApplicationCommand {
this.productId = productId; this.productId = productId;
} }
public LocalDate getSubmittedOnDate() {
return this.submittedOnDate;
}
public void setSubmittedOnDate(final LocalDate submittedOnDate) {
this.submittedOnDate = submittedOnDate;
}
public String getSubmittedOnNote() { public String getSubmittedOnNote() {
return this.submittedOnNote; return this.submittedOnNote;
} }
@@ -120,24 +111,6 @@ public class SubmitLoanApplicationCommand {
this.submittedOnNote = submittedOnNote; 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() { public LoanSchedule getLoanSchedule() {
return this.loanSchedule; return this.loanSchedule;
} }
@@ -162,130 +135,6 @@ public class SubmitLoanApplicationCommand {
this.currencyCode = currencyCode; 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() { public String getDateFormat() {
return dateFormat; return dateFormat;
} }
@@ -294,37 +143,223 @@ public class SubmitLoanApplicationCommand {
this.dateFormat = dateFormat; this.dateFormat = dateFormat;
} }
public String getSubmittedOnDateFormatted() { public Long getClientId() {
return submittedOnDateFormatted; return clientId;
} }
public void setSubmittedOnDateFormatted(String submittedOnDateFormatted) { public void setClientId(Long clientId) {
this.submittedOnDateFormatted = submittedOnDateFormatted; this.clientId = clientId;
} }
public String getPrincipalFormatted() { public String getLocale() {
return principalFormatted; return locale;
} }
public void setPrincipalFormatted(String principalFormatted) { public void setLocale(String locale) {
this.principalFormatted = principalFormatted; this.locale = locale;
} }
public String getInArrearsToleranceAmountFormatted() { public String getDigitsAfterDecimal() {
return inArrearsToleranceAmountFormatted; return digitsAfterDecimal;
} }
public void setInArrearsToleranceAmountFormatted( public void setDigitsAfterDecimal(String digitsAfterDecimal) {
String inArrearsToleranceAmountFormatted) { this.digitsAfterDecimal = digitsAfterDecimal;
this.inArrearsToleranceAmountFormatted = inArrearsToleranceAmountFormatted;
} }
public String getInterestRatePerPeriodFormatted() { public Integer getDigitsAfterDecimalValue() {
return interestRatePerPeriodFormatted; return digitsAfterDecimalValue;
} }
public void setInterestRatePerPeriodFormatted( public void setDigitsAfterDecimalValue(Integer digitsAfterDecimalValue) {
String interestRatePerPeriodFormatted) { this.digitsAfterDecimalValue = digitsAfterDecimalValue;
this.interestRatePerPeriodFormatted = interestRatePerPeriodFormatted; }
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;
} }
} }
@@ -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.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.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 # loan event and transactions screens
label.loan.on=On: label.loan.on=On:
label.loan.action.note=Note: 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.on=Repayment on:
label.loan.transaction.amount=Amount: label.loan.transaction.amount=Amount:
tab.client.account.loan.details=Details tab.client.account.loan.details=Details
tab.client.account.loan.schedule=Schedule tab.client.account.loan.schedule=Schedule
tab.client.account.loan.repayments=Repayments 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.expected.disbursement.date.on=Expected disbursement on:
form.label.loan.first.repayment.on=First repayment 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.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.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. validation.msg.loan.submitted.on.date.cannot.be.blank=Submitted on date cannot be blank.
@@ -55,9 +55,28 @@ $(document).ready(function() {
return false; return false;
} }
}, },
globalDate: function(localDateAsISOString) { globalDate: function(dateParts) {
try { 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 dateParts = localDateAsISOString.split("-")
var year = dateParts[0]; var year = dateParts[0];
var month = parseInt(dateParts[1]) - 1; // month is zero indexed var month = parseInt(dateParts[1]) - 1; // month is zero indexed
@@ -177,13 +196,13 @@ $(document).ready(function() {
}; };
function calculateAnnualPercentageRate() { function calculateAnnualPercentageRate() {
var periodInterestRate = parseFloat($('#interestRatePerPeriodFormatted').val()); var periodInterestRate = parseFloat($('#interestRatePerPeriod').val());
if (isNaN(periodInterestRate)) { if (isNaN(periodInterestRate)) {
periodInterestRate = 0; periodInterestRate = 0;
} }
var periodsInYear = 12; var periodsInYear = 12;
var periodType = $('#interestRateFrequencyMethod').val(); var periodType = $('#interestRateFrequencyType').val();
if (periodType == 3) { if (periodType == 3) {
periodsInYear = 1; periodsInYear = 1;
} else if (periodType == 2) { } else if (periodType == 2) {
@@ -207,7 +226,6 @@ $(document).ready(function() {
dataType: 'json', dataType: 'json',
cache: false, cache: false,
beforeSend: function(xhr) { beforeSend: function(xhr) {
console.log("base64: " + base64);
xhr.setRequestHeader("Authorization", "Basic " + base64); xhr.setRequestHeader("Authorization", "Basic " + base64);
}, },
success: function(data, textStatus, jqXHR) { success: function(data, textStatus, jqXHR) {
@@ -228,7 +246,7 @@ $(document).ready(function() {
calculateLoanSchedule(); calculateLoanSchedule();
// change detection // change detection
$('#principalFormatted').change(function() { $('#principal').change(function() {
calculateLoanSchedule(); calculateLoanSchedule();
}); });
@@ -236,7 +254,7 @@ $(document).ready(function() {
calculateLoanSchedule(); calculateLoanSchedule();
}); });
$('#repaymentFrequency').change(function() { $('#repaymentFrequencyType').change(function() {
calculateLoanSchedule(); calculateLoanSchedule();
}); });
@@ -244,37 +262,37 @@ $(document).ready(function() {
calculateLoanSchedule(); calculateLoanSchedule();
}); });
$('#expectedDisbursementDateFormatted').change(function() { $('#expectedDisbursementDate').change(function() {
calculateLoanSchedule(); calculateLoanSchedule();
}); });
$('#repaymentsStartingFromDateFormatted').change(function() { $('#repaymentsStartingFromDate').change(function() {
calculateLoanSchedule(); calculateLoanSchedule();
}); });
$('#interestRatePerPeriodFormatted').change(function() { $('#interestRatePerPeriod').change(function() {
calculateAnnualPercentageRate(); calculateAnnualPercentageRate();
calculateLoanSchedule(); calculateLoanSchedule();
}); });
$('#interestRateFrequencyMethod').change(function() { $('#interestRateFrequencyType').change(function() {
calculateAnnualPercentageRate(); calculateAnnualPercentageRate();
calculateLoanSchedule(); calculateLoanSchedule();
}); });
$('#amortizationMethod').change(function() { $('#amortizationType').change(function() {
calculateLoanSchedule(); calculateLoanSchedule();
}); });
$('#interestMethod').change(function() { $('#interestType').change(function() {
calculateLoanSchedule(); calculateLoanSchedule();
}); });
$('#interestCalculationPeriodMethod').change(function() { $('#interestCalculationPeriodType').change(function() {
calculateLoanSchedule(); calculateLoanSchedule();
}); });
$('#interestCalculatedFromDateFormatted').change(function() { $('#interestChargedFromDate').change(function() {
calculateLoanSchedule(); calculateLoanSchedule();
}); });
@@ -302,7 +320,6 @@ $(document).ready(function() {
var calculateLoanScheduleurl = baseApiUrl + 'loans?command=calculateLoanSchedule'; var calculateLoanScheduleurl = baseApiUrl + 'loans?command=calculateLoanSchedule';
var newFormData = JSON.stringify($('#entityform').serializeObject()); var newFormData = JSON.stringify($('#entityform').serializeObject());
console.log(newFormData);
var jqxhr2 = $.ajax({ var jqxhr2 = $.ajax({
url: calculateLoanScheduleurl, url: calculateLoanScheduleurl,
@@ -312,7 +329,6 @@ $(document).ready(function() {
data: newFormData, data: newFormData,
cache: false, cache: false,
beforeSend: function(xhr) { beforeSend: function(xhr) {
console.log("base64: " + base64);
xhr.setRequestHeader("Authorization", "Basic " + base64); xhr.setRequestHeader("Authorization", "Basic " + base64);
}, },
success: function(data, textStatus, jqXHR) { success: function(data, textStatus, jqXHR) {
@@ -332,7 +348,6 @@ $(document).ready(function() {
var submitLoanApplicationUrl = baseApiUrl + 'loans'; var submitLoanApplicationUrl = baseApiUrl + 'loans';
var newFormData = JSON.stringify($('#entityform').serializeObject()); var newFormData = JSON.stringify($('#entityform').serializeObject());
console.log(newFormData);
var jqxhr2 = $.ajax({ var jqxhr2 = $.ajax({
url: submitLoanApplicationUrl, url: submitLoanApplicationUrl,
@@ -342,11 +357,9 @@ $(document).ready(function() {
data: newFormData, data: newFormData,
cache: false, cache: false,
beforeSend: function(xhr) { beforeSend: function(xhr) {
console.log("base64: " + base64);
xhr.setRequestHeader("Authorization", "Basic " + base64); xhr.setRequestHeader("Authorization", "Basic " + base64);
}, },
beforeSend: function(xhr) { beforeSend: function(xhr) {
console.log("base64: " + base64);
xhr.setRequestHeader("Authorization", "Basic " + base64); xhr.setRequestHeader("Authorization", "Basic " + base64);
}, },
success: function(data, textStatus, jqXHR) { success: function(data, textStatus, jqXHR) {
@@ -368,7 +381,6 @@ $(document).ready(function() {
dataType: 'json', dataType: 'json',
cache: false, cache: false,
beforeSend: function(xhr) { beforeSend: function(xhr) {
console.log("base64: " + base64);
xhr.setRequestHeader("Authorization", "Basic " + base64); xhr.setRequestHeader("Authorization", "Basic " + base64);
}, },
success: function(data, textStatus, jqXHR) { success: function(data, textStatus, jqXHR) {
@@ -29,7 +29,7 @@
{{#each scheduledLoanInstallments}} {{#each scheduledLoanInstallments}}
<tr> <tr>
<td>{{=$ctx.number(installmentNumber)}}</td> <td>{{=$ctx.number(installmentNumber)}}</td>
<td>{{=$ctx.globalDate(periodEnd)}}</td> <td>{{=$ctx.globalDateAsISOString(periodEnd)}}</td>
<td>{{=$ctx.money(principalDue)}}</td> <td>{{=$ctx.money(principalDue)}}</td>
<td>{{=$ctx.money(interestDue)}}</td> <td>{{=$ctx.money(interestDue)}}</td>
<td>{{=$ctx.money(totalInstallmentDue)}}</td> <td>{{=$ctx.money(totalInstallmentDue)}}</td>
@@ -54,7 +54,7 @@
<form id="entityform"> <form id="entityform">
<div id="formerrors"></div> <div id="formerrors"></div>
<input type="hidden" id="applicantId" name="applicantId" value="{{=clientId}}" /> <input type="hidden" id="clientId" name="clientId" value="{{=clientId}}" />
<input type="hidden" id="currencyCode" name="currencyCode" value="{{=selectedProduct.principalMoney.currencyCode}}" /> <input type="hidden" id="currencyCode" name="currencyCode" value="{{=selectedProduct.principalMoney.currencyCode}}" />
<input type="hidden" id="digitsAfterDecimal" name="digitsAfterDecimal" value="{{=$ctx.number(selectedProduct.principalMoney.currencyDigitsAfterDecimal)}}" /> <input type="hidden" id="digitsAfterDecimal" name="digitsAfterDecimal" value="{{=$ctx.number(selectedProduct.principalMoney.currencyDigitsAfterDecimal)}}" />
@@ -84,8 +84,8 @@
<td style="text-align:right;vertical-align:bottom;width:50px;">&nbsp;</td> <td style="text-align:right;vertical-align:bottom;width:50px;">&nbsp;</td>
<td valign="top"> <td valign="top">
<input type="hidden" id="dateFormat" name="dateFormat" value="dd MMMM yyyy" /> <input type="hidden" id="dateFormat" name="dateFormat" value="dd MMMM yyyy" />
<label for="submittedOnDateFormatted"><spring:message code="form.label.loan.submitted.on"/></label> <label for="submittedOnDate"><spring:message code="form.label.loan.submitted.on"/></label>
<input id="submittedOnDateFormatted" name="submittedOnDateFormatted" title="" type="text" class="datepickerfield" value="{{=$ctx.globalDate(submittedOnDate)}}" /> <input id="submittedOnDate" name="submittedOnDate" title="" type="text" class="datepickerfield" value="{{=$ctx.globalDate(submittedOnDate)}}" />
<label for="submittedOnNote"><spring:message code="form.label.loan.submitted.on.note"/></label> <label for="submittedOnNote"><spring:message code="form.label.loan.submitted.on.note"/></label>
<textarea id="submittedOnNote" name="submittedOnNote" rows="2" cols="50" draggable="false">{{=submittedOnNote}}</textarea> <textarea id="submittedOnNote" name="submittedOnNote" rows="2" cols="50" draggable="false">{{=submittedOnNote}}</textarea>
@@ -103,7 +103,7 @@
<tr> <tr>
<td><spring:message code="form.label.loan.product.loan.amount"/></td> <td><spring:message code="form.label.loan.product.loan.amount"/></td>
<td> <td>
<input id="principalFormatted" name="principalFormatted" title="" type="text" value="{{=$ctx.money(selectedProduct.principalMoney)}}" style="width: 125px;" /> <input id="principal" name="principal" title="" type="text" value="{{=$ctx.money(selectedProduct.principalMoney)}}" style="width: 125px;" />
<input id="principalCurrencyCode" name="principalCurrencyCode" title="" type="text" value="{{=selectedProduct.principalMoney.displaySymbol}}" style="width: 40px;" disabled="disabled" /> <input id="principalCurrencyCode" name="principalCurrencyCode" title="" type="text" value="{{=selectedProduct.principalMoney.displaySymbol}}" style="width: 40px;" disabled="disabled" />
</td> </td>
</tr> </tr>
@@ -112,7 +112,7 @@
<td> <td>
<input id="repaymentEvery" name="repaymentEvery" title="" type="text" value="{{=$ctx.number(selectedProduct.repaidEvery)}}" style="width: 50px;" /> <input id="repaymentEvery" name="repaymentEvery" title="" type="text" value="{{=$ctx.number(selectedProduct.repaidEvery)}}" style="width: 50px;" />
<select name="repaymentFrequency" id="repaymentFrequency" title="" style="width: 121px;"> <select name="repaymentFrequencyType" id="repaymentFrequencyType" title="" style="width: 121px;">
{{#each selectedProduct.repaymentFrequencyOptions}} {{#each selectedProduct.repaymentFrequencyOptions}}
{{#if $ctx.number($parent.parent.data.selectedProduct.repaymentPeriodFrequency)===$ctx.number(id)}} {{#if $ctx.number($parent.parent.data.selectedProduct.repaymentPeriodFrequency)===$ctx.number(id)}}
<option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option> <option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option>
@@ -132,13 +132,13 @@
<tr> <tr>
<td><spring:message code="form.label.loan.expected.disbursement.date.on"/></td> <td><spring:message code="form.label.loan.expected.disbursement.date.on"/></td>
<td> <td>
<input id="expectedDisbursementDateFormatted" name="expectedDisbursementDateFormatted" title="" type="text" class="datepickerfield" value="{{=$ctx.globalDate(expectedDisbursementDate)}}" style="width:172px;"/> <input id="expectedDisbursementDate" name="expectedDisbursementDate" title="" type="text" class="datepickerfield" value="{{=$ctx.globalDate(expectedDisbursementDate)}}" style="width:172px;"/>
</td> </td>
</tr> </tr>
<tr> <tr>
<td><spring:message code="form.label.loan.first.repayment.on"/></td> <td><spring:message code="form.label.loan.first.repayment.on"/></td>
<td> <td>
<input id="repaymentsStartingFromDateFormatted" name="repaymentsStartingFromDateFormatted" title="" type="text" class="datepickerfield" value="{{=$ctx.globalDate(repaymentsStartingFromDate)}}" style="width:172px;"/> <input id="repaymentsStartingFromDate" name="repaymentsStartingFromDate" title="" type="text" class="datepickerfield" value="{{=$ctx.globalDate(repaymentsStartingFromDate)}}" style="width:172px;"/>
</td> </td>
</tr> </tr>
</table> </table>
@@ -149,9 +149,9 @@
<tr> <tr>
<td><spring:message code="form.label.loan.product.nominal.interestrate"/></td> <td><spring:message code="form.label.loan.product.nominal.interestrate"/></td>
<td> <td>
<input id="interestRatePerPeriodFormatted" name="interestRatePerPeriodFormatted" title="" type="text" value="{{=$ctx.decimal(selectedProduct.interestRatePerPeriod, 4)}}" style="width: 60px;" /> <input id="interestRatePerPeriod" name="interestRatePerPeriod" title="" type="text" value="{{=$ctx.decimal(selectedProduct.interestRatePerPeriod, 4)}}" style="width: 60px;" />
<select name="interestRateFrequencyMethod" id="interestRateFrequencyMethod" title="" style="width: 115px;"> <select name="interestRateFrequencyType" id="interestRateFrequencyType" title="" style="width: 115px;">
{{#each selectedProduct.interestFrequencyOptions}} {{#each selectedProduct.interestFrequencyOptions}}
{{#if $ctx.number($parent.parent.data.selectedProduct.interestRatePeriod)===$ctx.number(id)}} {{#if $ctx.number($parent.parent.data.selectedProduct.interestRatePeriod)===$ctx.number(id)}}
<option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option> <option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option>
@@ -171,7 +171,7 @@
<tr> <tr>
<td><spring:message code="form.label.loan.product.amortization"/></td> <td><spring:message code="form.label.loan.product.amortization"/></td>
<td> <td>
<select name="amortizationMethod" id="amortizationMethod" title="" style="width: 178px;"> <select name="amortizationType" id="amortizationType" title="" style="width: 178px;">
{{#each selectedProduct.possibleAmortizationOptions}} {{#each selectedProduct.possibleAmortizationOptions}}
{{#if $ctx.number($parent.parent.data.selectedProduct.amortizationMethod)===$ctx.number(id)}} {{#if $ctx.number($parent.parent.data.selectedProduct.amortizationMethod)===$ctx.number(id)}}
<option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option> <option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option>
@@ -185,7 +185,7 @@
<tr> <tr>
<td><spring:message code="form.label.loan.product.interest.method"/></td> <td><spring:message code="form.label.loan.product.interest.method"/></td>
<td> <td>
<select name="interestMethod" id="interestMethod" title="" style="width: 180px;"> <select name="interestType" id="interestType" title="" style="width: 180px;">
{{#each selectedProduct.possibleInterestOptions}} {{#each selectedProduct.possibleInterestOptions}}
{{#if $ctx.number($parent.parent.data.selectedProduct.interestMethod)===$ctx.number(id)}} {{#if $ctx.number($parent.parent.data.selectedProduct.interestMethod)===$ctx.number(id)}}
<option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option> <option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option>
@@ -199,7 +199,7 @@
<tr> <tr>
<td><spring:message code="form.label.loan.product.interest.rate.calcutated.in.period"/></td> <td><spring:message code="form.label.loan.product.interest.rate.calcutated.in.period"/></td>
<td> <td>
<select id="interestCalculationPeriodMethod" name="interestCalculationPeriodMethod" title="" style="width: 220px;"> <select id="interestCalculationPeriodType" name="interestCalculationPeriodType" title="" style="width: 220px;">
{{#each selectedProduct.possibleInterestRateCalculatedInPeriodOptions}} {{#each selectedProduct.possibleInterestRateCalculatedInPeriodOptions}}
{{#if $ctx.number($parent.parent.data.selectedProduct.interestRateCalculatedInPeriod)===$ctx.number(id)}} {{#if $ctx.number($parent.parent.data.selectedProduct.interestRateCalculatedInPeriod)===$ctx.number(id)}}
<option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option> <option value="{{=$ctx.number(id)}}" selected="selected">{{=value}}</option>
@@ -213,13 +213,13 @@
<tr> <tr>
<td><spring:message code="form.label.loan.interest.charged.from"/></td> <td><spring:message code="form.label.loan.interest.charged.from"/></td>
<td> <td>
<input id="interestCalculatedFromDateFormatted" name="interestCalculatedFromDateFormatted" title="" type="text" class="datepickerfield" value="{{=$ctx.globalDate(interestCalculatedFromDate)}}" style="width:172px;"/> <input id="interestChargedFromDate" name="interestChargedFromDate" title="" type="text" class="datepickerfield" value="{{=$ctx.globalDate(interestCalculatedFromDate)}}" style="width:172px;"/>
</td> </td>
</tr> </tr>
<tr> <tr>
<td><spring:message code="form.label.loan.product.arrears.tolerance"/></td> <td><spring:message code="form.label.loan.product.arrears.tolerance"/></td>
<td> <td>
<input id="inArrearsToleranceAmountFormatted" name="inArrearsToleranceAmountFormatted" title="" type="text" value="{{=$ctx.money(selectedProduct.inArrearsTolerance)}}" style="width: 125px;" /> <input id="inArrearsTolerance" name="inArrearsTolerance" title="" type="text" value="{{=$ctx.money(selectedProduct.inArrearsTolerance)}}" style="width: 125px;" />
<input id="inArrearsCurrencyCode" name="inArrearsCurrencyCode" title="" type="text" value="{{=selectedProduct.inArrearsTolerance.displaySymbol}}" style="width: 40px;" disabled="disabled" /> <input id="inArrearsCurrencyCode" name="inArrearsCurrencyCode" title="" type="text" value="{{=selectedProduct.inArrearsTolerance.displaySymbol}}" style="width: 40px;" disabled="disabled" />
</td> </td>
</tr> </tr>
@@ -19,8 +19,6 @@ import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat; import org.joda.time.format.ISODateTimeFormat;
import org.mifosng.data.LoanSchedule; 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.CalculateLoanScheduleCommand;
import org.mifosng.data.command.ImportLoanCommand; import org.mifosng.data.command.ImportLoanCommand;
import org.mifosng.data.command.ImportLoanRepaymentsCommand; 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.api.commands.ImportClientCommand;
import org.mifosng.platform.client.domain.Client; import org.mifosng.platform.client.domain.Client;
import org.mifosng.platform.client.domain.ClientRepository; 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.currency.domain.Money;
import org.mifosng.platform.exceptions.UnAuthenticatedUserException; 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.DefaultLoanLifecycleStateMachine;
import org.mifosng.platform.loan.domain.InterestCalculationPeriodMethod; 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.Loan;
import org.mifosng.platform.loan.domain.LoanLifecycleStateMachine; import org.mifosng.platform.loan.domain.LoanLifecycleStateMachine;
import org.mifosng.platform.loan.domain.LoanProduct; 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.LoanProductRepository;
import org.mifosng.platform.loan.domain.LoanRepaymentScheduleInstallment;
import org.mifosng.platform.loan.domain.LoanRepository; import org.mifosng.platform.loan.domain.LoanRepository;
import org.mifosng.platform.loan.domain.LoanStatus; import org.mifosng.platform.loan.domain.LoanStatus;
import org.mifosng.platform.loan.domain.LoanStatusRepository; import org.mifosng.platform.loan.domain.LoanStatusRepository;
import org.mifosng.platform.loan.domain.LoanTransaction; import org.mifosng.platform.loan.domain.LoanTransaction;
import org.mifosng.platform.loan.domain.PeriodFrequencyType; import org.mifosng.platform.loan.domain.PeriodFrequencyType;
import org.mifosng.platform.loan.service.CalculationPlatformService; 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.Office;
import org.mifosng.platform.organisation.domain.OfficeRepository; import org.mifosng.platform.organisation.domain.OfficeRepository;
import org.mifosng.platform.organisation.domain.Organisation; import org.mifosng.platform.organisation.domain.Organisation;
@@ -75,11 +69,13 @@ public class ImportPlatformServiceImpl implements ImportPlatformService {
private final CalculationPlatformService calculationPlatformService; private final CalculationPlatformService calculationPlatformService;
private final LoanRepository loanRepository; private final LoanRepository loanRepository;
private final LoanStatusRepository loanStatusRepository; private final LoanStatusRepository loanStatusRepository;
private final LoanAssembler loanAssembler;
@Autowired @Autowired
public ImportPlatformServiceImpl( public ImportPlatformServiceImpl(final LoanAssembler loanAssembler,
final OfficeRepository officeRepository, final ClientRepository clientRepository, final LoanProductRepository loanProductRepository, final OfficeRepository officeRepository, final ClientRepository clientRepository, final LoanProductRepository loanProductRepository,
final CalculationPlatformService calculationPlatformService, final LoanRepository loanRepository, final LoanStatusRepository loanStatusRepository) { final CalculationPlatformService calculationPlatformService, final LoanRepository loanRepository, final LoanStatusRepository loanStatusRepository) {
this.loanAssembler = loanAssembler;
this.officeRepository = officeRepository; this.officeRepository = officeRepository;
this.clientRepository = clientRepository; this.clientRepository = clientRepository;
this.loanProductRepository = loanProductRepository; this.loanProductRepository = loanProductRepository;
@@ -138,75 +134,10 @@ public class ImportPlatformServiceImpl implements ImportPlatformService {
SubmitLoanApplicationCommand command = combinedCommand.getSubmitLoanApplicationCommand(); SubmitLoanApplicationCommand command = combinedCommand.getSubmitLoanApplicationCommand();
// most of this code can be extracted out into an Assembler Loan loan = loanAssembler.assembleFrom(command, currentUser.getOrganisation());
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<ScheduledLoanInstallment> 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);
}
LoanLifecycleStateMachine loanLifecycleStateMachine = defaultLoanLifecycleStateMachine(); LoanLifecycleStateMachine loanLifecycleStateMachine = defaultLoanLifecycleStateMachine();
loan.submitApplication(command.getSubmittedOnDate(), command.getExpectedDisbursementDate(), command.getRepaymentsStartingFromDate(), command.getInterestCalculatedFromDate(), loanLifecycleStateMachine);
LoanStateTransitionCommand approveLoanCommand = combinedCommand.getApproveLoanCommand(); LoanStateTransitionCommand approveLoanCommand = combinedCommand.getApproveLoanCommand();
if (approveLoanCommand != null) { if (approveLoanCommand != null) {
loan.approve(approveLoanCommand.getEventDate(), loanLifecycleStateMachine); loan.approve(approveLoanCommand.getEventDate(), loanLifecycleStateMachine);
@@ -109,42 +109,42 @@ public class LoansApiResource {
@QueryParam("command") final String commandParam, @QueryParam("command") final String commandParam,
final SubmitLoanApplicationCommand command) { final SubmitLoanApplicationCommand command) {
LocalDate expectedDisbursementDate = apiDataConversionService LocalDate expectedDisbursementLocalDate = apiDataConversionService
.convertFrom(command.getExpectedDisbursementDateFormatted(), .convertFrom(command.getExpectedDisbursementDate(),
"expectedDisbursementDateFormatted", "expectedDisbursementDate",
command.getDateFormat()); command.getDateFormat());
LocalDate repaymentsStartingFromDate = apiDataConversionService LocalDate repaymentsStartingFromLocalDate = apiDataConversionService
.convertFrom(command.getRepaymentsStartingFromDateFormatted(), .convertFrom(command.getRepaymentsStartingFromDate(),
"repaymentsStartingFromDateFormatted", "repaymentsStartingFromDate",
command.getDateFormat()); command.getDateFormat());
LocalDate interestCalculatedFromDate = apiDataConversionService LocalDate interestChargedFromLocalDate = apiDataConversionService
.convertFrom(command.getInterestCalculatedFromDateFormatted(), .convertFrom(command.getInterestChargedFromDate(),
"interestCalculatedFromDateFormatted", "interestChargedFromDate",
command.getDateFormat()); command.getDateFormat());
LocalDate submittedOnDate = apiDataConversionService.convertFrom( LocalDate submittedOnLocalDate = apiDataConversionService.convertFrom(
command.getSubmittedOnDateFormatted(), command.getSubmittedOnDate(),
"submittedOnDateFormatted", command.getDateFormat()); "submittedOnDate", command.getDateFormat());
command.setExpectedDisbursementDate(expectedDisbursementDate);
command.setRepaymentsStartingFromDate(repaymentsStartingFromDate); command.setExpectedDisbursementLocalDate(expectedDisbursementLocalDate);
command.setInterestCalculatedFromDate(interestCalculatedFromDate); command.setRepaymentsStartingFromLocalDate(repaymentsStartingFromLocalDate);
command.setSubmittedOnDate(submittedOnDate); command.setInterestChargedFromLocalDate(interestChargedFromLocalDate);
command.setSubmittedOnLocalDate(submittedOnLocalDate);
// FIXME - pass in locale through query string or in 'request body' Locale clientApplicationLocale = this.apiDataConversionService.localeFromString(command.getLocale());
Locale clientApplicationLocale = Locale.UK; BigDecimal principalValue = this.apiDataConversionService.convertFrom(command.getPrincipal(), "principal", clientApplicationLocale);
BigDecimal principal = this.apiDataConversionService.convertFrom( BigDecimal inArrearsToleranceValue = this.apiDataConversionService.convertFrom(command.getInArrearsTolerance(), "inArrearsTolerance", clientApplicationLocale);
command.getPrincipalFormatted(), "principalFormatted", BigDecimal interestRatePerPeriodValue = this.apiDataConversionService.convertFrom(command.getInterestRatePerPeriod(),"interestRatePerPeriod", clientApplicationLocale);
clientApplicationLocale);
BigDecimal interestRatePerPeriod = this.apiDataConversionService Integer digitsAfterDecimalValue = this.apiDataConversionService.convertToInteger(command.getDigitsAfterDecimal(), "digitsAfterDecimal", clientApplicationLocale);
.convertFrom(command.getInterestRatePerPeriodFormatted(), Integer repaymentEveryValue = this.apiDataConversionService.convertToInteger(command.getRepaymentEvery(), "repaymentEvery", clientApplicationLocale);
"interestRatePerPeriodFormatted", Integer numberOfRepaymentsValue = this.apiDataConversionService.convertToInteger(command.getNumberOfRepayments(), "numberOfRepayments", clientApplicationLocale);
clientApplicationLocale);
BigDecimal inArrearsToleranceAmount = this.apiDataConversionService command.setPrincipalValue(principalValue);
.convertFrom(command.getInArrearsToleranceAmountFormatted(), command.setInArrearsToleranceValue(inArrearsToleranceValue);
"inArrearsToleranceAmountFormatted", command.setInterestRatePerPeriodValue(interestRatePerPeriodValue);
clientApplicationLocale); command.setDigitsAfterDecimalValue(digitsAfterDecimalValue);
command.setPrincipal(principal); command.setRepaymentEveryValue(repaymentEveryValue);
command.setInterestRatePerPeriod(interestRatePerPeriod); command.setNumberOfRepaymentsValue(numberOfRepaymentsValue);
command.setInArrearsToleranceAmount(inArrearsToleranceAmount);
CalculateLoanScheduleCommand calculateLoanScheduleCommand = command CalculateLoanScheduleCommand calculateLoanScheduleCommand = command
.toCalculateLoanScheduleCommand(); .toCalculateLoanScheduleCommand();
@@ -99,7 +99,7 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableCustom<Ap
Money interest = getInterest(totalAvailable.getCurrency()); Money interest = getInterest(totalAvailable.getCurrency());
Money principal = getPrincipal(totalAvailable.getCurrency()); Money principal = getPrincipal(totalAvailable.getCurrency());
// TODO - configuration around order components of loan are paid off in. // TODO - NEWFEATURE - configuration around order components of loan are paid off in.
// pay off interest // pay off interest
if (remaining.isGreaterThanOrEqualTo(interest)) { if (remaining.isGreaterThanOrEqualTo(interest)) {
this.interestCompleted = interest.getAmount(); this.interestCompleted = interest.getAmount();
@@ -3,13 +3,10 @@ package org.mifosng.platform.loan.service;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.mifosng.data.ApiParameterError; import org.mifosng.data.ApiParameterError;
import org.mifosng.data.command.CalculateLoanScheduleCommand; import org.mifosng.data.command.CalculateLoanScheduleCommand;
import org.mifosng.platform.DataValidatorBuilder;
import org.mifosng.platform.exceptions.PlatformApiDataValidationException; import org.mifosng.platform.exceptions.PlatformApiDataValidationException;
import org.mifosng.platform.loan.domain.AmortizationMethod;
import org.mifosng.platform.loan.domain.InterestMethod;
import org.mifosng.platform.loan.domain.PeriodFrequencyType;
public class CalculateLoanScheduleCommandValidator { public class CalculateLoanScheduleCommandValidator {
@@ -20,199 +17,53 @@ public class CalculateLoanScheduleCommandValidator {
} }
public void validate() { public void validate() {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>(); List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
if (StringUtils.isBlank(command.getCurrencyCode())) { DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.currency.cannot.be.empty", "The parameter currencyCode cannot be blank.", "currencyCode");
dataValidationErrors.add(error);
}
if (command.getDigitsAfterDecimal() != null) { baseDataValidator.reset().parameter("currencyCode").value(command.getCurrencyCode()).notBlank();
baseDataValidator.reset().parameter("digitsAfterDecimal").value(command.getDigitsAfterDecimalValue()).notNull().inMinMaxRange(0, 6);
if (command.getDigitsAfterDecimal() < 0 || command.getDigitsAfterDecimal() > 6) { baseDataValidator.reset().parameter("principal").value(command.getPrincipalValue()).notNull().positiveAmount();
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); baseDataValidator.reset().parameter("repaymentFrequencyType").value(command.getRepaymentFrequencyType()).notNull().inMinMaxRange(0, 3);
dataValidationErrors.add(error); baseDataValidator.reset().parameter("repaymentEvery").value(command.getRepaymentEveryValue()).notNull().greaterThanZero();
} baseDataValidator.reset().parameter("numberOfRepayments").value(command.getNumberOfRepaymentsValue()).notNull().greaterThanZero();
} else { baseDataValidator.reset().parameter("interestRatePerPeriod").value(command.getInterestRatePerPeriodValue()).notNull();
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.currency.digitsAfterDecimal.cannot.be.empty", "The parameter digitsAfterDecimal cannot be blank.", "digitsAfterDecimal"); baseDataValidator.reset().parameter("interestRateFrequencyType").value(command.getInterestRateFrequencyType()).notNull().inMinMaxRange(0, 3);
dataValidationErrors.add(error); 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)) baseDataValidator.reset().parameter("expectedDisbursementDate").value(command.getExpectedDisbursementLocalDate()).notNull();
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);
}
if (command.getRepaymentFrequency() != null) { if (command.getExpectedDisbursementLocalDate() != null) {
PeriodFrequencyType frequencyType = PeriodFrequencyType.fromInt(command.getRepaymentFrequency()); if (command.getRepaymentsStartingFromLocalDate() != null
ApiParameterError error = null; && command.getExpectedDisbursementLocalDate().isAfter(command.getRepaymentsStartingFromLocalDate())) {
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())) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.loan.expectedDisbursementDate.cannot.be.after.first.repayment.date", 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", "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); 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", 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); 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 // validate interestCalculatedFromDate is after or on repaymentsStartingFromDate
if (command.getExpectedDisbursementDate().isAfter(command.getInterestCalculatedFromDate())) { if (command.getExpectedDisbursementLocalDate().isAfter(command.getInterestChargedFromLocalDate())) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.loan.interestCalculatedFromDate.cannot.be.before.disbursement.date", 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.", "interestCalculatedFromDate", command.getInterestCalculatedFromDate(), command.getExpectedDisbursementDate()); "The parameter interestCalculatedFromDate cannot be before the date given for expected disbursement.", "interestChargedFromDate", command.getInterestChargedFromLocalDate(), command.getExpectedDisbursementLocalDate());
dataValidationErrors.add(error); 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()) { if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors); 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;
} }
} }
@@ -51,20 +51,19 @@ public class CalculationPlatformServiceImpl implements
CalculateLoanScheduleCommandValidator validator = new CalculateLoanScheduleCommandValidator(command); CalculateLoanScheduleCommandValidator validator = new CalculateLoanScheduleCommandValidator(command);
validator.validate(); validator.validate();
// assemble 'loan data' into 'domain' object [LoanProductRelatedDetail] final BigDecimal principalAmount = command.getPrincipalValue();
final BigDecimal principalAmount = BigDecimal.valueOf(command.getPrincipal().doubleValue()); final BigDecimal defaultNominalInterestRatePerPeriod = command.getInterestRatePerPeriodValue();
final BigDecimal defaultNominalInterestRatePerPeriod = BigDecimal.valueOf(command.getInterestRatePerPeriod().doubleValue()); final PeriodFrequencyType interestPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyType());
final PeriodFrequencyType interestPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyMethod()); final InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestType());
final InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestMethod()); final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command.getInterestCalculationPeriodType());
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command.getInterestCalculationPeriodMethod()); final Integer repayEvery = command.getRepaymentEveryValue();
final Integer repayEvery = command.getRepaymentEvery(); final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.fromInt(command.getRepaymentFrequencyType());
final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.fromInt(command.getRepaymentFrequency()); final Integer defaultNumberOfInstallments = command.getNumberOfRepaymentsValue();
final Integer defaultNumberOfInstallments = command.getNumberOfRepayments(); final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationType());
final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationMethod());
final BigDecimal defaultAnnualNominalInterestRate = this.aprCalculator.calculateFrom(interestPeriodFrequencyType, defaultNominalInterestRatePerPeriod); 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 // in arrerars tolerance isnt relevant when auto-calculating a loan schedule
final BigDecimal inArrearsTolerance = BigDecimal.ZERO; final BigDecimal inArrearsTolerance = BigDecimal.ZERO;
@@ -78,11 +77,11 @@ public class CalculationPlatformServiceImpl implements
LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(interestMethod); LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(interestMethod);
ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneByCode(command.getCurrencyCode()); 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()); applicationCurrency.getDisplaySymbol(), applicationCurrency.getNameCode());
return loanScheduleGenerator.generate(loanScheduleInfo, command.getExpectedDisbursementDate(), command.getRepaymentsStartingFromDate(), return loanScheduleGenerator.generate(loanScheduleInfo, command.getExpectedDisbursementLocalDate(), command.getRepaymentsStartingFromLocalDate(),
command.getInterestCalculatedFromDate(), currencyData); command.getInterestChargedFromLocalDate(), currencyData);
} }
@Override @Override
@@ -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<ScheduledLoanInstallment> 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<LoanStatus> allowedLoanStatuses = this.loanStatusRepository.findAll();
return new DefaultLoanLifecycleStateMachine(allowedLoanStatuses);
}
}
@@ -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')") @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); public EntityIdentifier makeLoanRepayment(LoanTransactionCommand command);
@PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')")
EntityIdentifier adjustLoanTransaction(AdjustLoanTransactionCommand command); EntityIdentifier adjustLoanTransaction(AdjustLoanTransactionCommand command);
@PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')")
EntityIdentifier waiveLoanAmount(LoanTransactionCommand command); EntityIdentifier waiveLoanAmount(LoanTransactionCommand command);
} }
@@ -2,7 +2,6 @@ package org.mifosng.platform.loan.service;
import static org.mifosng.platform.Specifications.loansThatMatch; import static org.mifosng.platform.Specifications.loansThatMatch;
import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -10,7 +9,6 @@ import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosng.data.EntityIdentifier; import org.mifosng.data.EntityIdentifier;
import org.mifosng.data.LoanSchedule; import org.mifosng.data.LoanSchedule;
import org.mifosng.data.MoneyData;
import org.mifosng.data.ScheduledLoanInstallment; import org.mifosng.data.ScheduledLoanInstallment;
import org.mifosng.data.command.AdjustLoanTransactionCommand; import org.mifosng.data.command.AdjustLoanTransactionCommand;
import org.mifosng.data.command.CalculateLoanScheduleCommand; 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.LoanTransactionCommand;
import org.mifosng.data.command.SubmitLoanApplicationCommand; import org.mifosng.data.command.SubmitLoanApplicationCommand;
import org.mifosng.data.command.UndoStateTransitionCommand; 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.Note;
import org.mifosng.platform.client.domain.NoteRepository; import org.mifosng.platform.client.domain.NoteRepository;
import org.mifosng.platform.currency.domain.MonetaryCurrency; 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.LoanNotFoundException;
import org.mifosng.platform.exceptions.NoAuthorizationException; import org.mifosng.platform.exceptions.NoAuthorizationException;
import org.mifosng.platform.exceptions.PlatformDomainRuleException; 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.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.Loan;
import org.mifosng.platform.loan.domain.LoanLifecycleStateMachine; 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.LoanRepaymentScheduleInstallment;
import org.mifosng.platform.loan.domain.LoanRepository; import org.mifosng.platform.loan.domain.LoanRepository;
import org.mifosng.platform.loan.domain.LoanStatus; 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.LoanTransaction;
import org.mifosng.platform.loan.domain.LoanTransactionRepository; import org.mifosng.platform.loan.domain.LoanTransactionRepository;
import org.mifosng.platform.loan.domain.PeriodFrequencyType; import org.mifosng.platform.loan.domain.PeriodFrequencyType;
import org.mifosng.platform.loanschedule.domain.AprCalculator;
import org.mifosng.platform.security.PlatformSecurityContext; import org.mifosng.platform.security.PlatformSecurityContext;
import org.mifosng.platform.user.domain.AppUser; import org.mifosng.platform.user.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -56,24 +45,21 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final LoanRepository loanRepository; private final LoanRepository loanRepository;
private final LoanProductRepository loanProductRepository;
private final LoanStatusRepository loanStatusRepository; private final LoanStatusRepository loanStatusRepository;
private final ClientRepository clientRepository;
private final NoteRepository noteRepository; private final NoteRepository noteRepository;
private final CalculationPlatformService calculationPlatformService; private final CalculationPlatformService calculationPlatformService;
private final AprCalculator aprCalculator = new AprCalculator();
private final LoanTransactionRepository loanTransactionRepository; private final LoanTransactionRepository loanTransactionRepository;
private final LoanAssembler loanAssembler;
@Autowired @Autowired
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final LoanAssembler loanAssembler,
final LoanRepository loanRepository, final LoanTransactionRepository loanTransactionRepository, final LoanRepository loanRepository, final LoanTransactionRepository loanTransactionRepository,
final LoanStatusRepository loanStatusRepository, final LoanProductRepository loanProductRepository, final LoanStatusRepository loanStatusRepository,
final ClientRepository clientRepository, final NoteRepository noteRepository, final CalculationPlatformService calculationPlatformService) { final NoteRepository noteRepository, final CalculationPlatformService calculationPlatformService) {
this.context = context; this.context = context;
this.loanAssembler = loanAssembler;
this.loanRepository = loanRepository; this.loanRepository = loanRepository;
this.loanTransactionRepository = loanTransactionRepository; this.loanTransactionRepository = loanTransactionRepository;
this.loanProductRepository = loanProductRepository;
this.clientRepository = clientRepository;
this.loanStatusRepository = loanStatusRepository; this.loanStatusRepository = loanStatusRepository;
this.noteRepository = noteRepository; this.noteRepository = noteRepository;
this.calculationPlatformService = calculationPlatformService; this.calculationPlatformService = calculationPlatformService;
@@ -97,55 +83,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
SubmitLoanApplicationCommandValidator validator = new SubmitLoanApplicationCommandValidator(command); SubmitLoanApplicationCommandValidator validator = new SubmitLoanApplicationCommandValidator(command);
validator.validate(); 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")) { if (this.isBeforeToday(submittedOn) && currentUser.hasNotPermissionForAnyOf("CAN_SUBMIT_HISTORIC_LOAN_APPLICATION_ROLE", "PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE")) {
throw new NoAuthorizationException("Cannot add backdated loan."); 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. Loan loan = loanAssembler.assembleFrom(command, currentUser.getOrganisation());
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());
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<ScheduledLoanInstallment> 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); this.loanRepository.save(loan);
if (StringUtils.isNotBlank(command.getSubmittedOnNote())) { if (StringUtils.isNotBlank(command.getSubmittedOnNote())) {
@@ -25,15 +25,15 @@ public class SubmitLoanApplicationCommandValidator {
dataValidationErrors.add(error); dataValidationErrors.add(error);
} }
if (command.getSubmittedOnDate() == null) { if (command.getSubmittedOnLocalDate() == null) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.loan.submitted.on.date.cannot.be.blank", 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); dataValidationErrors.add(error);
} else { } 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", 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", "The date of parameter submittedOnDate cannot fall after the date given for expectedDisbursementDate.", "submittedOnDate",
command.getSubmittedOnDateFormatted(), command.getExpectedDisbursementDateFormatted()); command.getSubmittedOnDate(), command.getExpectedDisbursementDate());
dataValidationErrors.add(error); dataValidationErrors.add(error);
} }
} }
@@ -41,17 +41,17 @@ public class SubmitLoanApplicationCommandValidator {
try { try {
// reuse calculate loan schedule validator for now // reuse calculate loan schedule validator for now
CalculateLoanScheduleCommand calculateLoanScheduleCommand = new CalculateLoanScheduleCommand( CalculateLoanScheduleCommand calculateLoanScheduleCommand = new CalculateLoanScheduleCommand(
command.getCurrencyCode(), command.getDigitsAfterDecimal(), command.getCurrencyCode(), command.getDigitsAfterDecimalValue(),
command.getPrincipal(), command.getInterestRatePerPeriod(), command.getPrincipalValue(), command.getInterestRatePerPeriodValue(),
command.getInterestRateFrequencyMethod(), command.getInterestRateFrequencyType(),
command.getInterestMethod(), command.getInterestCalculationPeriodMethod(), command.getInterestType(), command.getInterestCalculationPeriodType(),
command.getRepaymentEvery(), command.getRepaymentEveryValue(),
command.getRepaymentFrequency(), command.getRepaymentFrequencyType(),
command.getNumberOfRepayments(), command.getNumberOfRepaymentsValue(),
command.getAmortizationMethod(), command.getAmortizationType(),
command.getExpectedDisbursementDate(), command.getExpectedDisbursementLocalDate(),
command.getRepaymentsStartingFromDate(), command.getRepaymentsStartingFromLocalDate(),
command.getInterestCalculatedFromDate()); command.getInterestChargedFromLocalDate());
CalculateLoanScheduleCommandValidator validator = new CalculateLoanScheduleCommandValidator( CalculateLoanScheduleCommandValidator validator = new CalculateLoanScheduleCommandValidator(
calculateLoanScheduleCommand); calculateLoanScheduleCommand);
@@ -9,7 +9,6 @@ import org.mifosng.platform.loan.domain.LoanProductRelatedDetail;
public class PmtCalculator { public class PmtCalculator {
public Money calculatePaymentForOnePeriodFrom(LoanProductRelatedDetail loanScheduleInfo, BigDecimal periodInterestRateForRepaymentPeriod, MonetaryCurrency monetaryCurrency) { public Money calculatePaymentForOnePeriodFrom(LoanProductRelatedDetail loanScheduleInfo, BigDecimal periodInterestRateForRepaymentPeriod, MonetaryCurrency monetaryCurrency) {
// TODO - check if going to doubles is a problem
double interestRateFraction = periodInterestRateForRepaymentPeriod.doubleValue(); double interestRateFraction = periodInterestRateForRepaymentPeriod.doubleValue();
double futureValue = 0; double futureValue = 0;
@@ -24,7 +23,6 @@ public class PmtCalculator {
} }
public Money calculateTotalRepaymentFrom(LoanProductRelatedDetail loanScheduleInfo, BigDecimal periodInterestRateForRepaymentPeriod, MonetaryCurrency monetaryCurrency) { public Money calculateTotalRepaymentFrom(LoanProductRelatedDetail loanScheduleInfo, BigDecimal periodInterestRateForRepaymentPeriod, MonetaryCurrency monetaryCurrency) {
// TODO - check if going to doubles is a problem
double interestRateFraction = periodInterestRateForRepaymentPeriod.doubleValue(); double interestRateFraction = periodInterestRateForRepaymentPeriod.doubleValue();
double futureValue = 0; double futureValue = 0;
@@ -44,7 +44,6 @@ public class RoleReadPlatformServiceImpl implements RoleReadPlatformService {
return this.jdbcTemplate.query(sql, mapper, new Object[] {currentUser.getOrganisation().getId() }); return this.jdbcTemplate.query(sql, mapper, new Object[] {currentUser.getOrganisation().getId() });
} }
// FIXME - does it make sense to use JDBC over repository for this?
@Override @Override
public RoleData retrieveRole(final Long id) { public RoleData retrieveRole(final Long id) {
AppUser currentUser = context.authenticatedUser(); AppUser currentUser = context.authenticatedUser();