calc loans arrears for details page
This commit is contained in:
@@ -27,10 +27,10 @@ import org.mifosng.platform.api.data.LoanAccountData;
|
||||
import org.mifosng.platform.api.data.LoanAccountSummaryData;
|
||||
import org.mifosng.platform.api.data.LoanBasicDetailsData;
|
||||
import org.mifosng.platform.api.data.LoanPermissionData;
|
||||
import org.mifosng.platform.api.data.LoanRepaymentPeriodDatajpw;
|
||||
import org.mifosng.platform.api.data.LoanRepaymentPeriodData;
|
||||
import org.mifosng.platform.api.data.LoanSchedule;
|
||||
import org.mifosng.platform.api.data.LoanTransactionData;
|
||||
import org.mifosng.platform.api.data.LoanTransactionDatajpw;
|
||||
import org.mifosng.platform.api.data.LoanTransactionDataDTO;
|
||||
import org.mifosng.platform.api.data.NewLoanData;
|
||||
import org.mifosng.platform.api.infrastructure.ApiDataConversionService;
|
||||
import org.mifosng.platform.api.infrastructure.ApiJSONFormattingService;
|
||||
@@ -99,9 +99,9 @@ public class LoansApiResource {
|
||||
LoanBasicDetailsData loanBasicDetails = this.loanReadPlatformService
|
||||
.retrieveLoanAccountDetails(loanId);
|
||||
|
||||
Collection<LoanTransactionDatajpw> loanRepayments = this.loanReadPlatformService
|
||||
Collection<LoanTransactionDataDTO> loanRepayments = this.loanReadPlatformService
|
||||
.retrieveLoanPayments(loanId);
|
||||
Collection<LoanRepaymentPeriodDatajpw> repaymentSchedule = this.loanReadPlatformService
|
||||
Collection<LoanRepaymentPeriodData> repaymentSchedule = this.loanReadPlatformService
|
||||
.retrieveRepaymentSchedule(loanId);
|
||||
|
||||
LoanAccountSummaryData summary = this.loanReadPlatformService
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
package org.mifosng.platform.api.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DerivedLoanData {
|
||||
|
||||
private LoanRepaymentScheduleData repaymentSchedule;
|
||||
private LoanAccountSummaryData summary;
|
||||
private List<LoanTransactionData> loanRepayments;
|
||||
|
||||
public DerivedLoanData() {
|
||||
//
|
||||
}
|
||||
|
||||
public DerivedLoanData(LoanRepaymentScheduleData repaymentScheduleData, LoanAccountSummaryData summaryData, List<LoanTransactionData> loanRepayments) {
|
||||
this.repaymentSchedule = repaymentScheduleData;
|
||||
this.summary = summaryData;
|
||||
this.loanRepayments = loanRepayments;
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleData getRepaymentSchedule() {
|
||||
return repaymentSchedule;
|
||||
}
|
||||
|
||||
public void setRepaymentSchedule(LoanRepaymentScheduleData repaymentSchedule) {
|
||||
this.repaymentSchedule = repaymentSchedule;
|
||||
}
|
||||
|
||||
public LoanAccountSummaryData getSummary() {
|
||||
return summary;
|
||||
}
|
||||
|
||||
public void setSummary(LoanAccountSummaryData summary) {
|
||||
this.summary = summary;
|
||||
}
|
||||
|
||||
public List<LoanTransactionData> getLoanRepayments() {
|
||||
return loanRepayments;
|
||||
}
|
||||
|
||||
public void setLoanRepayments(List<LoanTransactionData> loanRepayments) {
|
||||
this.loanRepayments = loanRepayments;
|
||||
}
|
||||
}
|
||||
@@ -44,8 +44,8 @@ public class LoanAccountData {
|
||||
private LocalDate lifeCycleStatusDate;
|
||||
|
||||
private LoanAccountSummaryData summary;
|
||||
private Collection<LoanRepaymentPeriodDatajpw> repaymentSchedule;
|
||||
private Collection<LoanTransactionDatajpw> loanRepayments;
|
||||
private Collection<LoanRepaymentPeriodData> repaymentSchedule;
|
||||
private Collection<LoanTransactionDataDTO> loanRepayments;
|
||||
|
||||
private LoanPermissionData permissions;
|
||||
|
||||
@@ -57,8 +57,8 @@ public class LoanAccountData {
|
||||
|
||||
public LoanAccountData(LoanBasicDetailsData basicDetails,
|
||||
LoanAccountSummaryData summary,
|
||||
Collection<LoanRepaymentPeriodDatajpw> repaymentSchedule,
|
||||
Collection<LoanTransactionDatajpw> loanRepayments,
|
||||
Collection<LoanRepaymentPeriodData> repaymentSchedule,
|
||||
Collection<LoanTransactionDataDTO> loanRepayments,
|
||||
LoanPermissionData permissions) {
|
||||
this.summary = summary;
|
||||
this.repaymentSchedule = repaymentSchedule;
|
||||
@@ -141,21 +141,21 @@ public class LoanAccountData {
|
||||
this.summary = summary;
|
||||
}
|
||||
|
||||
public Collection<LoanRepaymentPeriodDatajpw> getRepaymentSchedule() {
|
||||
public Collection<LoanRepaymentPeriodData> getRepaymentSchedule() {
|
||||
return repaymentSchedule;
|
||||
}
|
||||
|
||||
public void setRepaymentSchedule(
|
||||
Collection<LoanRepaymentPeriodDatajpw> repaymentSchedule) {
|
||||
Collection<LoanRepaymentPeriodData> repaymentSchedule) {
|
||||
this.repaymentSchedule = repaymentSchedule;
|
||||
}
|
||||
|
||||
public Collection<LoanTransactionDatajpw> getLoanRepayments() {
|
||||
public Collection<LoanTransactionDataDTO> getLoanRepayments() {
|
||||
return loanRepayments;
|
||||
}
|
||||
|
||||
public void setLoanRepayments(
|
||||
Collection<LoanTransactionDatajpw> loanRepayments) {
|
||||
Collection<LoanTransactionDataDTO> loanRepayments) {
|
||||
this.loanRepayments = loanRepayments;
|
||||
}
|
||||
|
||||
|
||||
+35
-128
@@ -4,9 +4,9 @@ import org.joda.time.LocalDate;
|
||||
|
||||
public class LoanRepaymentPeriodData {
|
||||
|
||||
private Long loanId;
|
||||
private Integer period;
|
||||
private LocalDate date;
|
||||
private MoneyData disbursed;
|
||||
private MoneyData principal;
|
||||
private MoneyData principalPaid;
|
||||
private MoneyData principalOutstanding;
|
||||
@@ -16,70 +16,36 @@ public class LoanRepaymentPeriodData {
|
||||
private MoneyData total;
|
||||
private MoneyData totalPaid;
|
||||
private MoneyData totalOutstanding;
|
||||
private MoneyData totalWaived;
|
||||
private MoneyData totalArrears;
|
||||
private LocalDate arrearsFrom;
|
||||
private LocalDate arrearsTo;
|
||||
private LocalDate paidInFullOn;
|
||||
private LocalDate lastAffectingPaymentOn;
|
||||
|
||||
private static CurrencyData currencyData(MoneyData moneyData) {
|
||||
String code = moneyData.getCurrencyCode();
|
||||
String name = moneyData.getDefaultName();
|
||||
int decimalPlaces = moneyData.getDigitsAfterDecimal();
|
||||
String displaySymbol = moneyData.getDisplaySymbol();
|
||||
String nameCode = moneyData.getNameCode();
|
||||
return new CurrencyData(code, name, decimalPlaces, displaySymbol, nameCode);
|
||||
}
|
||||
|
||||
public LoanRepaymentPeriodData() {
|
||||
//
|
||||
}
|
||||
|
||||
public LoanRepaymentPeriodData(Integer period, LocalDate date,
|
||||
MoneyData disbursed, MoneyData total) {
|
||||
this.period = period;
|
||||
this.date = date;
|
||||
this.disbursed = disbursed;
|
||||
this.principal = null;
|
||||
this.principalPaid = null;
|
||||
this.principalOutstanding = null;
|
||||
this.interest = null;
|
||||
this.interestPaid = null;
|
||||
this.interestOutstanding = null;
|
||||
this.total = total;
|
||||
this.totalPaid = null;
|
||||
this.totalOutstanding = total;
|
||||
}
|
||||
|
||||
public LoanRepaymentPeriodData(Integer period, LocalDate date,
|
||||
MoneyData disbursed, MoneyData principal,
|
||||
MoneyData interest, MoneyData total,
|
||||
MoneyData totalOutstanding) {
|
||||
public LoanRepaymentPeriodData(Long loanId, Integer period,
|
||||
LocalDate date, MoneyData principal, MoneyData principalPaid,
|
||||
MoneyData principalOutstanding, MoneyData interest,
|
||||
MoneyData interestPaid, MoneyData interestOutstanding,
|
||||
MoneyData total, MoneyData totalPaid, MoneyData totalOutstanding) {
|
||||
this.loanId = loanId;
|
||||
this.period = period;
|
||||
this.date = date;
|
||||
this.disbursed = disbursed;
|
||||
this.principal = principal;
|
||||
this.principalPaid = MoneyData.zero(currencyData(principal));
|
||||
this.principalOutstanding = principal;
|
||||
this.principalPaid = principalPaid;
|
||||
this.principalOutstanding = principalOutstanding;
|
||||
this.interest = interest;
|
||||
this.interestPaid = MoneyData.zero(currencyData(principal));
|
||||
this.interestOutstanding = interest;
|
||||
this.interestPaid = interestPaid;
|
||||
this.interestOutstanding = interestOutstanding;
|
||||
this.total = total;
|
||||
this.totalPaid = MoneyData.zero(currencyData(principal));
|
||||
this.totalPaid = totalPaid;
|
||||
this.totalOutstanding = totalOutstanding;
|
||||
}
|
||||
|
||||
public boolean isInArrearsWithToleranceOf(MoneyData arrearsTolerance, LocalDate asOf) {
|
||||
|
||||
boolean inArrears = false;
|
||||
if (arrearsTolerance.isGreaterThanZero()) {
|
||||
inArrears = this.totalOutstanding.isGreaterThan(arrearsTolerance);
|
||||
} else {
|
||||
inArrears = this.totalOutstanding.isGreaterThanZero();
|
||||
}
|
||||
|
||||
return inArrears && this.date.isBefore(asOf);
|
||||
|
||||
public Long getLoanId() {
|
||||
return loanId;
|
||||
}
|
||||
|
||||
public void setLoanId(Long loanId) {
|
||||
this.loanId = loanId;
|
||||
}
|
||||
|
||||
public Integer getPeriod() {
|
||||
@@ -98,14 +64,6 @@ public class LoanRepaymentPeriodData {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public MoneyData getDisbursed() {
|
||||
return disbursed;
|
||||
}
|
||||
|
||||
public void setDisbursed(MoneyData disbursed) {
|
||||
this.disbursed = disbursed;
|
||||
}
|
||||
|
||||
public MoneyData getPrincipal() {
|
||||
return principal;
|
||||
}
|
||||
@@ -114,22 +72,6 @@ public class LoanRepaymentPeriodData {
|
||||
this.principal = principal;
|
||||
}
|
||||
|
||||
public MoneyData getInterest() {
|
||||
return interest;
|
||||
}
|
||||
|
||||
public void setInterest(MoneyData interest) {
|
||||
this.interest = interest;
|
||||
}
|
||||
|
||||
public MoneyData getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public void setTotal(MoneyData total) {
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
public MoneyData getPrincipalPaid() {
|
||||
return principalPaid;
|
||||
}
|
||||
@@ -146,6 +88,14 @@ public class LoanRepaymentPeriodData {
|
||||
this.principalOutstanding = principalOutstanding;
|
||||
}
|
||||
|
||||
public MoneyData getInterest() {
|
||||
return interest;
|
||||
}
|
||||
|
||||
public void setInterest(MoneyData interest) {
|
||||
this.interest = interest;
|
||||
}
|
||||
|
||||
public MoneyData getInterestPaid() {
|
||||
return interestPaid;
|
||||
}
|
||||
@@ -162,6 +112,14 @@ public class LoanRepaymentPeriodData {
|
||||
this.interestOutstanding = interestOutstanding;
|
||||
}
|
||||
|
||||
public MoneyData getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public void setTotal(MoneyData total) {
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
public MoneyData getTotalPaid() {
|
||||
return totalPaid;
|
||||
}
|
||||
@@ -178,55 +136,4 @@ public class LoanRepaymentPeriodData {
|
||||
this.totalOutstanding = totalOutstanding;
|
||||
}
|
||||
|
||||
public boolean isFullyPaid() {
|
||||
return this.totalOutstanding.isZero();
|
||||
}
|
||||
|
||||
public MoneyData getTotalArrears() {
|
||||
return totalArrears;
|
||||
}
|
||||
|
||||
public void setTotalArrears(MoneyData totalArrears) {
|
||||
this.totalArrears = totalArrears;
|
||||
}
|
||||
|
||||
public LocalDate getArrearsFrom() {
|
||||
return arrearsFrom;
|
||||
}
|
||||
|
||||
public void setArrearsFrom(LocalDate arrearsFrom) {
|
||||
this.arrearsFrom = arrearsFrom;
|
||||
}
|
||||
|
||||
public LocalDate getArrearsTo() {
|
||||
return arrearsTo;
|
||||
}
|
||||
|
||||
public void setArrearsTo(LocalDate arrearsTo) {
|
||||
this.arrearsTo = arrearsTo;
|
||||
}
|
||||
|
||||
public LocalDate getPaidInFullOn() {
|
||||
return paidInFullOn;
|
||||
}
|
||||
|
||||
public void setPaidInFullOn(LocalDate paidInFullOn) {
|
||||
this.paidInFullOn = paidInFullOn;
|
||||
}
|
||||
|
||||
public LocalDate getLastAffectingPaymentOn() {
|
||||
return lastAffectingPaymentOn;
|
||||
}
|
||||
|
||||
public void setLastAffectingPaymentOn(LocalDate lastAffectingPaymentOn) {
|
||||
this.lastAffectingPaymentOn = lastAffectingPaymentOn;
|
||||
}
|
||||
|
||||
public MoneyData getTotalWaived() {
|
||||
return totalWaived;
|
||||
}
|
||||
|
||||
public void setTotalWaived(MoneyData totalWaived) {
|
||||
this.totalWaived = totalWaived;
|
||||
}
|
||||
}
|
||||
-139
@@ -1,139 +0,0 @@
|
||||
package org.mifosng.platform.api.data;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
public class LoanRepaymentPeriodDatajpw {
|
||||
|
||||
private Long loanId;
|
||||
private Integer period;
|
||||
private LocalDate date;
|
||||
private MoneyData principal;
|
||||
private MoneyData principalPaid;
|
||||
private MoneyData principalOutstanding;
|
||||
private MoneyData interest;
|
||||
private MoneyData interestPaid;
|
||||
private MoneyData interestOutstanding;
|
||||
private MoneyData total;
|
||||
private MoneyData totalPaid;
|
||||
private MoneyData totalOutstanding;
|
||||
|
||||
public LoanRepaymentPeriodDatajpw() {
|
||||
//
|
||||
}
|
||||
|
||||
public LoanRepaymentPeriodDatajpw(Long loanId, Integer period,
|
||||
LocalDate date, MoneyData principal, MoneyData principalPaid,
|
||||
MoneyData principalOutstanding, MoneyData interest,
|
||||
MoneyData interestPaid, MoneyData interestOutstanding,
|
||||
MoneyData total, MoneyData totalPaid, MoneyData totalOutstanding) {
|
||||
this.loanId = loanId;
|
||||
this.period = period;
|
||||
this.date = date;
|
||||
this.principal = principal;
|
||||
this.principalPaid = principalPaid;
|
||||
this.principalOutstanding = principalOutstanding;
|
||||
this.interest = interest;
|
||||
this.interestPaid = interestPaid;
|
||||
this.interestOutstanding = interestOutstanding;
|
||||
this.total = total;
|
||||
this.totalPaid = totalPaid;
|
||||
this.totalOutstanding = totalOutstanding;
|
||||
}
|
||||
|
||||
public Long getLoanId() {
|
||||
return loanId;
|
||||
}
|
||||
|
||||
public void setLoanId(Long loanId) {
|
||||
this.loanId = loanId;
|
||||
}
|
||||
|
||||
public Integer getPeriod() {
|
||||
return period;
|
||||
}
|
||||
|
||||
public void setPeriod(Integer period) {
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
public LocalDate getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(LocalDate date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public MoneyData getPrincipal() {
|
||||
return principal;
|
||||
}
|
||||
|
||||
public void setPrincipal(MoneyData principal) {
|
||||
this.principal = principal;
|
||||
}
|
||||
|
||||
public MoneyData getPrincipalPaid() {
|
||||
return principalPaid;
|
||||
}
|
||||
|
||||
public void setPrincipalPaid(MoneyData principalPaid) {
|
||||
this.principalPaid = principalPaid;
|
||||
}
|
||||
|
||||
public MoneyData getPrincipalOutstanding() {
|
||||
return principalOutstanding;
|
||||
}
|
||||
|
||||
public void setPrincipalOutstanding(MoneyData principalOutstanding) {
|
||||
this.principalOutstanding = principalOutstanding;
|
||||
}
|
||||
|
||||
public MoneyData getInterest() {
|
||||
return interest;
|
||||
}
|
||||
|
||||
public void setInterest(MoneyData interest) {
|
||||
this.interest = interest;
|
||||
}
|
||||
|
||||
public MoneyData getInterestPaid() {
|
||||
return interestPaid;
|
||||
}
|
||||
|
||||
public void setInterestPaid(MoneyData interestPaid) {
|
||||
this.interestPaid = interestPaid;
|
||||
}
|
||||
|
||||
public MoneyData getInterestOutstanding() {
|
||||
return interestOutstanding;
|
||||
}
|
||||
|
||||
public void setInterestOutstanding(MoneyData interestOutstanding) {
|
||||
this.interestOutstanding = interestOutstanding;
|
||||
}
|
||||
|
||||
public MoneyData getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public void setTotal(MoneyData total) {
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
public MoneyData getTotalPaid() {
|
||||
return totalPaid;
|
||||
}
|
||||
|
||||
public void setTotalPaid(MoneyData totalPaid) {
|
||||
this.totalPaid = totalPaid;
|
||||
}
|
||||
|
||||
public MoneyData getTotalOutstanding() {
|
||||
return totalOutstanding;
|
||||
}
|
||||
|
||||
public void setTotalOutstanding(MoneyData totalOutstanding) {
|
||||
this.totalOutstanding = totalOutstanding;
|
||||
}
|
||||
|
||||
}
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
package org.mifosng.platform.api.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LoanRepaymentScheduleData {
|
||||
|
||||
private List<LoanRepaymentPeriodData> periods = new ArrayList<LoanRepaymentPeriodData>();
|
||||
|
||||
public LoanRepaymentScheduleData() {
|
||||
//
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleData(
|
||||
final List<LoanRepaymentPeriodData> periods) {
|
||||
this.periods = periods;
|
||||
}
|
||||
|
||||
public List<LoanRepaymentPeriodData> getPeriods() {
|
||||
return periods;
|
||||
}
|
||||
|
||||
public void setPeriods(List<LoanRepaymentPeriodData> periods) {
|
||||
this.periods = periods;
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -2,18 +2,18 @@ package org.mifosng.platform.api.data;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
public class LoanTransactionDatajpw {
|
||||
public class LoanTransactionDataDTO {
|
||||
|
||||
private Long id;
|
||||
private EnumOptionData transactionType;
|
||||
private LocalDate date;
|
||||
private MoneyData total;
|
||||
|
||||
public LoanTransactionDatajpw() {
|
||||
public LoanTransactionDataDTO() {
|
||||
//
|
||||
}
|
||||
|
||||
public LoanTransactionDatajpw(Long id, EnumOptionData transactionType,
|
||||
public LoanTransactionDataDTO(Long id, EnumOptionData transactionType,
|
||||
final LocalDate date, final MoneyData total) {
|
||||
this.id = id;
|
||||
this.transactionType = transactionType;
|
||||
-491
@@ -1,491 +0,0 @@
|
||||
package org.mifosng.platform.loan.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosng.platform.api.data.CurrencyData;
|
||||
import org.mifosng.platform.api.data.DerivedLoanData;
|
||||
import org.mifosng.platform.api.data.EnumOptionData;
|
||||
import org.mifosng.platform.api.data.LoanAccountSummaryData;
|
||||
import org.mifosng.platform.api.data.LoanTransactionData;
|
||||
import org.mifosng.platform.api.data.LoanRepaymentPeriodData;
|
||||
import org.mifosng.platform.api.data.LoanRepaymentScheduleData;
|
||||
import org.mifosng.platform.api.data.MoneyData;
|
||||
import org.mifosng.platform.currency.domain.MonetaryCurrency;
|
||||
import org.mifosng.platform.currency.domain.Money;
|
||||
import org.mifosng.platform.loanproduct.service.LoanEnumerations;
|
||||
|
||||
// FIXME - The derived details of the loan schedule are now updated on the fly when someone does a transaction against a loan. So this is not fully needed.
|
||||
// - we still use this to figure out how much of a given transactions amount was principal versus interest but might not need this and we should probably
|
||||
// - derive and update that on the database on the fly
|
||||
// FIXME - JPW - the above fixme was done and I can't see anything else using this method or whole class
|
||||
public class DerivedLoanDataProcessor {
|
||||
|
||||
public DerivedLoanData process(List<LoanRepaymentScheduleInstallment> repaymentSchedulePeriods, List<LoanTransaction> loanTransactions,
|
||||
CurrencyData currencyDetail, BigDecimal arrearsTolerance) {
|
||||
|
||||
// 1. derive repayment schedule
|
||||
LoanRepaymentScheduleData repaymentScheduleDetails = generateRepaymentScheduleData(repaymentSchedulePeriods, currencyDetail);
|
||||
List<LoanRepaymentPeriodData> loanRepaymentPeriods = repaymentScheduleDetails.getPeriods();
|
||||
|
||||
// break up payments based on principal and interest
|
||||
List<LoanTransactionData> loanRepayments = new ArrayList<LoanTransactionData>();
|
||||
int repaymentScheduleIndex = 0;
|
||||
for (LoanTransaction transaction : loanTransactions) {
|
||||
if (transaction.isRepayment() || transaction.isWaiver()) {
|
||||
|
||||
MonetaryCurrency currency = new MonetaryCurrency(currencyDetail.getCode(), currencyDetail.getDecimalPlaces());
|
||||
|
||||
if (transaction.getAmount(currency).isGreaterThanZero()) {
|
||||
LoanRepaymentPeriodData scheduledRepaymentPeriod = loanRepaymentPeriods
|
||||
.get(repaymentScheduleIndex);
|
||||
|
||||
if (transaction.isRepayment()) {
|
||||
LoanTransactionData repaymentData = processLoanRepayment(
|
||||
transaction, scheduledRepaymentPeriod,
|
||||
repaymentScheduleIndex, loanRepaymentPeriods,
|
||||
arrearsTolerance, currencyDetail);
|
||||
loanRepayments.add(repaymentData);
|
||||
}
|
||||
|
||||
if (transaction.isWaiver()) {
|
||||
LoanTransactionData repaymentData = processWaiver(transaction, scheduledRepaymentPeriod, currencyDetail);
|
||||
loanRepayments.add(repaymentData);
|
||||
}
|
||||
|
||||
if (scheduledRepaymentPeriod.isFullyPaid()) {
|
||||
repaymentScheduleIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loanRepaymentPeriods = calculateArrears(loanRepaymentPeriods, arrearsTolerance, currencyDetail);
|
||||
|
||||
LoanRepaymentScheduleData processRepaymentScheduleData = new LoanRepaymentScheduleData(loanRepaymentPeriods);
|
||||
LoanAccountSummaryData summaryData = calculateTotalsFromRepaymentScheduleData(loanRepaymentPeriods, currencyDetail);
|
||||
|
||||
Collections.sort(loanRepayments, new LoanRepaymentDataComparator());
|
||||
|
||||
if (loanRepayments.isEmpty()) {
|
||||
loanRepayments = null;
|
||||
}
|
||||
|
||||
return new DerivedLoanData(processRepaymentScheduleData, summaryData, loanRepayments);
|
||||
}
|
||||
|
||||
private LoanTransactionData processWaiver(LoanTransaction transaction,
|
||||
LoanRepaymentPeriodData scheduledRepaymentPeriod, CurrencyData currencyData) {
|
||||
|
||||
MonetaryCurrency currency = new MonetaryCurrency(currencyData.getCode(), currencyData.getDecimalPlaces());
|
||||
Money totalToWaive = transaction.getAmount(currency);
|
||||
|
||||
Money interestToWaive = moneyFrom(scheduledRepaymentPeriod.getInterestOutstanding());
|
||||
Money principalToWaive = moneyFrom(scheduledRepaymentPeriod.getPrincipalOutstanding());
|
||||
|
||||
Money interestWaived = Money.zero(currency);
|
||||
|
||||
if (totalToWaive.isGreaterThanOrEqualTo(interestToWaive)) {
|
||||
totalToWaive = totalToWaive.minus(interestToWaive);
|
||||
interestWaived = interestToWaive;
|
||||
} else {
|
||||
interestWaived = totalToWaive;
|
||||
totalToWaive = Money.zero(currency);
|
||||
}
|
||||
|
||||
Money principalWaived = Money.zero(currency);
|
||||
if (totalToWaive.isGreaterThanOrEqualTo(principalToWaive)) {
|
||||
totalToWaive = totalToWaive.minus(principalToWaive);
|
||||
principalWaived = principalToWaive;
|
||||
} else {
|
||||
principalWaived = totalToWaive;
|
||||
totalToWaive = Money.zero(currency);
|
||||
}
|
||||
|
||||
MoneyData zero = moneyDataFrom(currencyData, Money.zero(currency));
|
||||
|
||||
Money totalWaivedInPeriodToDate = Money.zero(currency);
|
||||
if (scheduledRepaymentPeriod.getTotalWaived() != null) {
|
||||
totalWaivedInPeriodToDate = moneyFrom(scheduledRepaymentPeriod.getTotalWaived());
|
||||
}
|
||||
Money totalWaivedInTransaction = interestWaived.plus(principalWaived);
|
||||
totalWaivedInPeriodToDate = totalWaivedInPeriodToDate.plus(totalWaivedInTransaction);
|
||||
scheduledRepaymentPeriod.setTotalWaived(moneyDataFrom(currencyData, totalWaivedInPeriodToDate));
|
||||
|
||||
MoneyData totalWaived = moneyDataFrom(currencyData, totalWaivedInTransaction);
|
||||
|
||||
Money principalOutstanding = moneyFrom(scheduledRepaymentPeriod.getPrincipalOutstanding());
|
||||
Money remainingPrincipalOutstanding = principalOutstanding.minus(principalWaived);
|
||||
scheduledRepaymentPeriod.setPrincipalOutstanding(moneyDataFrom(currencyData, remainingPrincipalOutstanding));
|
||||
|
||||
Money interestOutstanding = moneyFrom(scheduledRepaymentPeriod.getInterestOutstanding());
|
||||
Money remainingInterestOutstanding = interestOutstanding.minus(interestWaived);
|
||||
scheduledRepaymentPeriod.setInterestOutstanding(moneyDataFrom(currencyData, remainingInterestOutstanding));
|
||||
|
||||
Money totalOutstanding = moneyFrom(scheduledRepaymentPeriod.getTotalOutstanding());
|
||||
Money remainingOutstanding = totalOutstanding.minus(moneyFrom(totalWaived));
|
||||
scheduledRepaymentPeriod.setTotalOutstanding(moneyDataFrom(currencyData, remainingOutstanding));
|
||||
|
||||
EnumOptionData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WAIVED);
|
||||
LoanTransactionData loanRepaymentData = new LoanTransactionData(transaction.getId(), transactionType, transaction.getTransactionDate(), moneyDataFrom(currencyData, principalWaived),
|
||||
moneyDataFrom(currencyData, interestWaived), totalWaived, zero);
|
||||
loanRepaymentData.setTotalWaived(totalWaived);
|
||||
return loanRepaymentData;
|
||||
}
|
||||
|
||||
private List<LoanRepaymentPeriodData> calculateArrears(
|
||||
List<LoanRepaymentPeriodData> loanRepaymentPeriods,
|
||||
BigDecimal arrearsTolerance, CurrencyData currencyData) {
|
||||
|
||||
LocalDate today = new LocalDate();
|
||||
int repaymentIndex = 0;
|
||||
for (LoanRepaymentPeriodData currentRepaymentSchedule : loanRepaymentPeriods) {
|
||||
if (currentRepaymentSchedule.isInArrearsWithToleranceOf(
|
||||
MoneyData.of(currencyData, arrearsTolerance), today)) {
|
||||
currentRepaymentSchedule
|
||||
.setTotalArrears(currentRepaymentSchedule
|
||||
.getTotalOutstanding());
|
||||
|
||||
LocalDate arrearsFrom = determineInArrearsFrom(currentRepaymentSchedule, loanRepaymentPeriods, repaymentIndex);
|
||||
|
||||
LocalDate arrearsTo = determineInArrearsTo(loanRepaymentPeriods, repaymentIndex);
|
||||
|
||||
currentRepaymentSchedule.setArrearsFrom(arrearsFrom);
|
||||
currentRepaymentSchedule.setArrearsTo(arrearsTo);
|
||||
}
|
||||
|
||||
repaymentIndex++;
|
||||
}
|
||||
|
||||
return loanRepaymentPeriods;
|
||||
}
|
||||
|
||||
private LocalDate determineInArrearsTo(
|
||||
List<LoanRepaymentPeriodData> loanRepaymentPeriods,
|
||||
int repaymentIndex) {
|
||||
|
||||
LocalDate today = new LocalDate();
|
||||
LocalDate arrearsDate = null;
|
||||
|
||||
if (loanRepaymentPeriods.size() - 1 > repaymentIndex) {
|
||||
LoanRepaymentPeriodData nextRepaymentSchedule = loanRepaymentPeriods
|
||||
.get(repaymentIndex);
|
||||
|
||||
arrearsDate = nextRepaymentSchedule.getDate().minusDays(1);
|
||||
}
|
||||
|
||||
if (loanRepaymentPeriods.size() - 1 == repaymentIndex) {
|
||||
arrearsDate = today;
|
||||
}
|
||||
|
||||
return arrearsDate;
|
||||
}
|
||||
|
||||
private LocalDate determineInArrearsFrom(
|
||||
LoanRepaymentPeriodData currentRepaymentSchedule,
|
||||
List<LoanRepaymentPeriodData> loanRepaymentPeriods,
|
||||
int repaymentIndex) {
|
||||
|
||||
|
||||
int previousScheduleIndex = repaymentIndex - 1;
|
||||
LocalDate arrearsDate = null;
|
||||
if (currentRepaymentSchedule.getLastAffectingPaymentOn() != null) {
|
||||
|
||||
if (currentRepaymentSchedule.getLastAffectingPaymentOn().isAfter(
|
||||
currentRepaymentSchedule.getDate())) {
|
||||
|
||||
if (loanRepaymentPeriods.size() - 1 > previousScheduleIndex && previousScheduleIndex > -1) {
|
||||
LoanRepaymentPeriodData lastRepaymentSchedule = loanRepaymentPeriods
|
||||
.get(previousScheduleIndex);
|
||||
arrearsDate = lastRepaymentSchedule.getDate().plusDays(1);
|
||||
} else {
|
||||
arrearsDate = currentRepaymentSchedule.getDate().minusMonths(1);
|
||||
}
|
||||
|
||||
} else {
|
||||
arrearsDate = currentRepaymentSchedule.getLastAffectingPaymentOn();
|
||||
}
|
||||
} else {
|
||||
if (loanRepaymentPeriods.size() - 1 > previousScheduleIndex && previousScheduleIndex > -1) {
|
||||
LoanRepaymentPeriodData lastRepaymentSchedule = loanRepaymentPeriods
|
||||
.get(previousScheduleIndex);
|
||||
arrearsDate = lastRepaymentSchedule.getDate().plusDays(1);
|
||||
} else {
|
||||
arrearsDate = currentRepaymentSchedule.getDate().minusMonths(1);
|
||||
}
|
||||
}
|
||||
|
||||
return arrearsDate;
|
||||
}
|
||||
|
||||
private LoanAccountSummaryData calculateTotalsFromRepaymentScheduleData(
|
||||
List<LoanRepaymentPeriodData> loanRepaymentPeriods, CurrencyData currencyData) {
|
||||
|
||||
MonetaryCurrency monetaryCurrency = new MonetaryCurrency(currencyData.getCode(), currencyData.getDecimalPlaces());
|
||||
|
||||
Money principalExpected = Money.zero(monetaryCurrency);
|
||||
Money principalPaid = Money.zero(monetaryCurrency);
|
||||
Money principalOutstanding = Money.zero(monetaryCurrency);
|
||||
|
||||
Money interestExpected = Money.zero(monetaryCurrency);
|
||||
Money interestPaid = Money.zero(monetaryCurrency);
|
||||
Money interestOutstanding = Money.zero(monetaryCurrency);
|
||||
|
||||
Money totalExpected = Money.zero(monetaryCurrency);
|
||||
Money totalPaid = Money.zero(monetaryCurrency);
|
||||
Money totalOutstanding = Money.zero(monetaryCurrency);
|
||||
|
||||
Money totalInArrears = Money.zero(monetaryCurrency);
|
||||
Money totalWaived = Money.zero(monetaryCurrency);
|
||||
|
||||
|
||||
for (LoanRepaymentPeriodData period : loanRepaymentPeriods) {
|
||||
|
||||
principalExpected = principalExpected.plus(moneyFrom(period.getPrincipal()));
|
||||
principalPaid = principalPaid.plus(moneyFrom(period.getPrincipalPaid()));
|
||||
principalOutstanding = principalOutstanding.plus(moneyFrom(period.getPrincipalOutstanding()));
|
||||
|
||||
interestExpected = interestExpected.plus(moneyFrom(period.getInterest()));
|
||||
interestPaid = interestPaid.plus(moneyFrom(period.getInterestPaid()));
|
||||
interestOutstanding = interestOutstanding.plus(moneyFrom(period.getInterestOutstanding()));
|
||||
|
||||
totalExpected = totalExpected.plus(moneyFrom(period.getTotal()));
|
||||
totalPaid = totalPaid.plus(moneyFrom(period.getTotalPaid()));
|
||||
totalOutstanding = totalOutstanding.plus(moneyFrom(period.getTotalOutstanding()));
|
||||
|
||||
if (period.getTotalWaived() != null) {
|
||||
totalWaived = totalWaived.plus(moneyFrom(period.getTotalWaived()));
|
||||
}
|
||||
|
||||
if (period.getTotalArrears() != null) {
|
||||
totalInArrears = totalInArrears.plus(moneyFrom(period.getTotalArrears()));
|
||||
}
|
||||
}
|
||||
|
||||
return new LoanAccountSummaryData(moneyDataFrom(currencyData, principalExpected), moneyDataFrom(currencyData, principalPaid),
|
||||
moneyDataFrom(currencyData, principalOutstanding), moneyDataFrom(currencyData, interestExpected),
|
||||
moneyDataFrom(currencyData, interestPaid), moneyDataFrom(currencyData, interestOutstanding),
|
||||
moneyDataFrom(currencyData, totalExpected), moneyDataFrom(currencyData, totalPaid), moneyDataFrom(currencyData, totalOutstanding),
|
||||
moneyDataFrom(currencyData, totalInArrears), moneyDataFrom(currencyData, totalWaived));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO - pays off interest first then principal so should make this configurable when generating 'derived view of loan account'
|
||||
*/
|
||||
private LoanTransactionData processLoanRepayment(LoanTransaction repayment,
|
||||
LoanRepaymentPeriodData scheduledRepayment,
|
||||
int repaymentScheduleIndex,
|
||||
List<LoanRepaymentPeriodData> repaymentSchedulePeriods,
|
||||
BigDecimal arrearsTolerance, CurrencyData currencyDetail) {
|
||||
|
||||
MoneyData zero = MoneyData.zero(currencyDetail);
|
||||
MoneyData cumulativeInterestPaid = MoneyData.zero(currencyDetail);
|
||||
MoneyData cumulativePrincipalPaid = MoneyData.zero(currencyDetail);
|
||||
|
||||
LoanRepaymentPeriodData currentRepaymentSchedule = scheduledRepayment;
|
||||
int currentRepaymentScheduleIndex = repaymentScheduleIndex;
|
||||
MoneyData overpaid = null;
|
||||
|
||||
MonetaryCurrency currency = new MonetaryCurrency(currencyDetail.getCode(), currencyDetail.getDecimalPlaces());
|
||||
|
||||
Money remaining = repayment.getAmount(currency);
|
||||
while (remaining.isGreaterThanZero()) {
|
||||
|
||||
Money interestOutstanding = moneyFrom(currentRepaymentSchedule.getInterestOutstanding());
|
||||
Money principalOutstanding = moneyFrom(currentRepaymentSchedule.getPrincipalOutstanding());
|
||||
|
||||
// pay off interest component
|
||||
if (remaining.isGreaterThanOrEqualTo(interestOutstanding)) {
|
||||
Money previousInterestPaid = moneyFrom(cumulativeInterestPaid);
|
||||
cumulativeInterestPaid = moneyDataFrom(currencyDetail, previousInterestPaid.plus(interestOutstanding));
|
||||
|
||||
MoneyData interestPaid = moneyDataFrom(currencyDetail, interestOutstanding);
|
||||
|
||||
Money paidToDate = moneyFrom(currentRepaymentSchedule.getInterestPaid());
|
||||
Money amountPaid = moneyFrom(interestPaid);
|
||||
|
||||
paidToDate = paidToDate.plus(amountPaid);
|
||||
|
||||
MoneyData totalInterest = moneyDataFrom(currencyDetail, paidToDate);
|
||||
currentRepaymentSchedule.setInterestPaid(totalInterest);
|
||||
|
||||
currentRepaymentSchedule.setInterestOutstanding(zero);
|
||||
|
||||
Money totalPaidToDate = moneyFrom(currentRepaymentSchedule.getTotalPaid());
|
||||
totalPaidToDate = totalPaidToDate.plus(interestOutstanding);
|
||||
|
||||
currentRepaymentSchedule.setTotalPaid(moneyDataFrom(currencyDetail, totalPaidToDate));
|
||||
|
||||
Money outstanding = moneyFrom(currentRepaymentSchedule.getTotal()).minus(moneyFrom(currentRepaymentSchedule.getTotalPaid()));
|
||||
currentRepaymentSchedule.setTotalOutstanding(moneyDataFrom(currencyDetail, outstanding));
|
||||
|
||||
if (interestOutstanding.isGreaterThanZero()) {
|
||||
currentRepaymentSchedule.setLastAffectingPaymentOn(repayment.getTransactionDate());
|
||||
}
|
||||
|
||||
remaining = remaining.minus(interestOutstanding);
|
||||
} else {
|
||||
// partial payment of principal
|
||||
Money previousInterestPaid = moneyFrom(cumulativeInterestPaid);
|
||||
cumulativeInterestPaid = moneyDataFrom(currencyDetail, previousInterestPaid.plus(remaining));
|
||||
|
||||
MoneyData interestPaid = moneyDataFrom(currencyDetail, remaining);
|
||||
|
||||
Money paidToDate = moneyFrom(currentRepaymentSchedule.getInterestPaid());
|
||||
Money amountPaid = moneyFrom(interestPaid);
|
||||
|
||||
paidToDate = paidToDate.plus(amountPaid);
|
||||
|
||||
MoneyData totalInterest = moneyDataFrom(currencyDetail, paidToDate);
|
||||
currentRepaymentSchedule.setInterestPaid(totalInterest);
|
||||
|
||||
interestOutstanding = interestOutstanding.minus(amountPaid);
|
||||
|
||||
currentRepaymentSchedule.setInterestOutstanding(moneyDataFrom(currencyDetail, interestOutstanding));
|
||||
|
||||
Money totalPaidToDate = moneyFrom(currentRepaymentSchedule.getTotalPaid());
|
||||
totalPaidToDate = totalPaidToDate.plus(amountPaid);
|
||||
|
||||
currentRepaymentSchedule.setTotalPaid(moneyDataFrom(currencyDetail, totalPaidToDate));
|
||||
|
||||
Money outstanding = moneyFrom(currentRepaymentSchedule.getTotal()).minus(moneyFrom(currentRepaymentSchedule.getTotalPaid()));
|
||||
currentRepaymentSchedule.setTotalOutstanding(moneyDataFrom(currencyDetail, outstanding));
|
||||
|
||||
if (interestPaid.isGreaterThanZero()) {
|
||||
currentRepaymentSchedule.setLastAffectingPaymentOn(repayment.getTransactionDate());
|
||||
}
|
||||
|
||||
remaining = remaining.minus(amountPaid);
|
||||
}
|
||||
|
||||
// pay off principal component
|
||||
if (remaining.isGreaterThanOrEqualTo(principalOutstanding)) {
|
||||
Money previousPrincipalPaid = moneyFrom(cumulativePrincipalPaid);
|
||||
cumulativePrincipalPaid = moneyDataFrom(currencyDetail, previousPrincipalPaid.plus(principalOutstanding));
|
||||
|
||||
MoneyData principalPaid = moneyDataFrom(currencyDetail, principalOutstanding);
|
||||
|
||||
Money paidToDate = moneyFrom(currentRepaymentSchedule.getPrincipalPaid());
|
||||
Money amountPaid = moneyFrom(principalPaid);
|
||||
|
||||
paidToDate = paidToDate.plus(amountPaid);
|
||||
|
||||
MoneyData totalPrincipal = moneyDataFrom(currencyDetail, paidToDate);
|
||||
currentRepaymentSchedule.setPrincipalPaid(totalPrincipal);
|
||||
currentRepaymentSchedule.setPrincipalOutstanding(zero);
|
||||
|
||||
Money totalPaidToDate = moneyFrom(currentRepaymentSchedule.getTotalPaid());
|
||||
totalPaidToDate = totalPaidToDate.plus(principalOutstanding);
|
||||
|
||||
currentRepaymentSchedule.setTotalPaid(moneyDataFrom(currencyDetail, totalPaidToDate));
|
||||
|
||||
Money outstanding = moneyFrom(currentRepaymentSchedule.getTotal()).minus(moneyFrom(currentRepaymentSchedule.getTotalPaid()));
|
||||
currentRepaymentSchedule.setTotalOutstanding(moneyDataFrom(currencyDetail, outstanding));
|
||||
|
||||
remaining = remaining.minus(principalOutstanding);
|
||||
} else {
|
||||
// partial payment of principal
|
||||
Money previousPrincipalPaid = moneyFrom(cumulativePrincipalPaid);
|
||||
cumulativePrincipalPaid = moneyDataFrom(currencyDetail, previousPrincipalPaid.plus(remaining));
|
||||
|
||||
MoneyData principalPaid = moneyDataFrom(currencyDetail, remaining);
|
||||
|
||||
Money paidToDate = moneyFrom(currentRepaymentSchedule.getPrincipalPaid());
|
||||
Money amountPaid = moneyFrom(principalPaid);
|
||||
|
||||
paidToDate = paidToDate.plus(amountPaid);
|
||||
|
||||
MoneyData totalPrincipal = moneyDataFrom(currencyDetail, paidToDate);
|
||||
currentRepaymentSchedule.setPrincipalPaid(totalPrincipal);
|
||||
|
||||
principalOutstanding = principalOutstanding.minus(amountPaid);
|
||||
currentRepaymentSchedule.setPrincipalOutstanding(moneyDataFrom(currencyDetail, principalOutstanding));
|
||||
|
||||
Money totalPaidToDate = moneyFrom(currentRepaymentSchedule.getTotalPaid());
|
||||
totalPaidToDate = totalPaidToDate.plus(amountPaid);
|
||||
|
||||
currentRepaymentSchedule.setTotalPaid(moneyDataFrom(currencyDetail, totalPaidToDate));
|
||||
Money outstanding = moneyFrom(currentRepaymentSchedule.getTotal()).minus(moneyFrom(currentRepaymentSchedule.getTotalPaid()));
|
||||
currentRepaymentSchedule.setTotalOutstanding(moneyDataFrom(currencyDetail, outstanding));
|
||||
|
||||
if (principalPaid.isGreaterThanZero()) {
|
||||
currentRepaymentSchedule.setLastAffectingPaymentOn(repayment.getTransactionDate());
|
||||
}
|
||||
|
||||
remaining = remaining.minus(amountPaid);
|
||||
}
|
||||
|
||||
// mark schedule as paid in full
|
||||
if (currentRepaymentSchedule.isFullyPaid()) {
|
||||
currentRepaymentSchedule.setPaidInFullOn(repayment.getTransactionDate());
|
||||
}
|
||||
|
||||
// check if this installment has
|
||||
if (currentRepaymentSchedule.isInArrearsWithToleranceOf(MoneyData.of(currencyDetail, arrearsTolerance), repayment.getTransactionDate())) {
|
||||
currentRepaymentSchedule.setTotalArrears(currentRepaymentSchedule.getTotalOutstanding());
|
||||
} else {
|
||||
currentRepaymentSchedule.setTotalArrears(MoneyData.zero(currencyDetail));
|
||||
}
|
||||
|
||||
if (remaining.isGreaterThanZero()) {
|
||||
currentRepaymentScheduleIndex++;
|
||||
if (repaymentSchedulePeriods.size() > currentRepaymentScheduleIndex) {
|
||||
currentRepaymentSchedule = repaymentSchedulePeriods.get(currentRepaymentScheduleIndex);
|
||||
} else {
|
||||
// loan has been overpaid by an amount so
|
||||
overpaid = moneyDataFrom(currencyDetail, remaining);
|
||||
// note - maybe should set the overpayment 'amount' against repayment period.
|
||||
remaining = Money.zero(remaining.getCurrency());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Money totalInterestComponent = moneyFrom(cumulativeInterestPaid);
|
||||
Money totalPrincipalComponent= moneyFrom(cumulativePrincipalPaid);
|
||||
|
||||
MoneyData totalPaid = moneyDataFrom(currencyDetail, totalPrincipalComponent.plus(totalInterestComponent));
|
||||
|
||||
EnumOptionData transactionType = LoanEnumerations.transactionType(LoanTransactionType.REPAYMENT);
|
||||
LoanTransactionData loanRepaymentData = new LoanTransactionData(repayment.getId(), transactionType, repayment.getTransactionDate(), cumulativePrincipalPaid, cumulativeInterestPaid, totalPaid, overpaid);
|
||||
return loanRepaymentData;
|
||||
}
|
||||
|
||||
private LoanRepaymentScheduleData generateRepaymentScheduleData(
|
||||
List<LoanRepaymentScheduleInstallment> repaymentSchedulePeriods,
|
||||
CurrencyData currencyData) {
|
||||
|
||||
MoneyData zero = MoneyData.zero(currencyData);
|
||||
|
||||
MonetaryCurrency currency = new MonetaryCurrency(currencyData.getCode(), currencyData.getDecimalPlaces());
|
||||
|
||||
List<LoanRepaymentPeriodData> loanScheduleDetails = new ArrayList<LoanRepaymentPeriodData>();
|
||||
|
||||
for (LoanRepaymentScheduleInstallment scheduledRepayment : repaymentSchedulePeriods) {
|
||||
|
||||
MoneyData principal = MoneyData.of(currencyData, scheduledRepayment.getPrincipal(currency).getAmount());
|
||||
MoneyData interest = MoneyData.of(currencyData, scheduledRepayment.getInterest(currency).getAmount());
|
||||
MoneyData total = MoneyData.of(currencyData, scheduledRepayment.getTotal(currency).getAmount());
|
||||
|
||||
LoanRepaymentPeriodData periodData = new LoanRepaymentPeriodData(
|
||||
scheduledRepayment.getInstallmentNumber(),
|
||||
scheduledRepayment.getDueDate(), zero, principal, interest,
|
||||
total, total);
|
||||
|
||||
loanScheduleDetails.add(periodData);
|
||||
}
|
||||
|
||||
return new LoanRepaymentScheduleData(loanScheduleDetails);
|
||||
}
|
||||
|
||||
private Money moneyFrom(MoneyData money) {
|
||||
MonetaryCurrency monetaryCurrency = new MonetaryCurrency(money.getCurrencyCode(), money.getDigitsAfterDecimal());
|
||||
return Money.of(monetaryCurrency, money.getAmount());
|
||||
}
|
||||
|
||||
private MoneyData moneyDataFrom(CurrencyData currencyData, Money money) {
|
||||
return MoneyData.of(currencyData, money.getAmount());
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -5,9 +5,9 @@ import java.util.Collection;
|
||||
import org.mifosng.platform.api.data.LoanAccountSummaryData;
|
||||
import org.mifosng.platform.api.data.LoanBasicDetailsData;
|
||||
import org.mifosng.platform.api.data.LoanPermissionData;
|
||||
import org.mifosng.platform.api.data.LoanRepaymentPeriodDatajpw;
|
||||
import org.mifosng.platform.api.data.LoanRepaymentPeriodData;
|
||||
import org.mifosng.platform.api.data.LoanTransactionData;
|
||||
import org.mifosng.platform.api.data.LoanTransactionDatajpw;
|
||||
import org.mifosng.platform.api.data.LoanTransactionDataDTO;
|
||||
import org.mifosng.platform.api.data.MoneyData;
|
||||
import org.mifosng.platform.api.data.NewLoanData;
|
||||
|
||||
@@ -15,13 +15,13 @@ public interface LoanReadPlatformService {
|
||||
|
||||
LoanBasicDetailsData retrieveLoanAccountDetails(Long loanId);
|
||||
|
||||
Collection<LoanRepaymentPeriodDatajpw> retrieveRepaymentSchedule(Long loanId);
|
||||
Collection<LoanRepaymentPeriodData> retrieveRepaymentSchedule(Long loanId);
|
||||
|
||||
Collection<LoanTransactionDatajpw> retrieveLoanPayments(Long loanId);
|
||||
Collection<LoanTransactionDataDTO> retrieveLoanPayments(Long loanId);
|
||||
|
||||
LoanAccountSummaryData retrieveSummary(MoneyData principal,
|
||||
Collection<LoanRepaymentPeriodDatajpw> repaymentSchedule,
|
||||
Collection<LoanTransactionDatajpw> loanRepayments);
|
||||
Collection<LoanRepaymentPeriodData> repaymentSchedule,
|
||||
Collection<LoanTransactionDataDTO> loanRepayments);
|
||||
|
||||
LoanPermissionData retrieveLoanPermissions(
|
||||
LoanBasicDetailsData loanBasicDetails, boolean isWaiverAllowed,
|
||||
|
||||
+20
-17
@@ -15,9 +15,9 @@ import org.mifosng.platform.api.data.LoanBasicDetailsData;
|
||||
import org.mifosng.platform.api.data.LoanPermissionData;
|
||||
import org.mifosng.platform.api.data.LoanProductData;
|
||||
import org.mifosng.platform.api.data.LoanProductLookup;
|
||||
import org.mifosng.platform.api.data.LoanRepaymentPeriodDatajpw;
|
||||
import org.mifosng.platform.api.data.LoanRepaymentPeriodData;
|
||||
import org.mifosng.platform.api.data.LoanTransactionData;
|
||||
import org.mifosng.platform.api.data.LoanTransactionDatajpw;
|
||||
import org.mifosng.platform.api.data.LoanTransactionDataDTO;
|
||||
import org.mifosng.platform.api.data.MoneyData;
|
||||
import org.mifosng.platform.api.data.NewLoanData;
|
||||
import org.mifosng.platform.client.service.ClientReadPlatformService;
|
||||
@@ -90,7 +90,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<LoanRepaymentPeriodDatajpw> retrieveRepaymentSchedule(
|
||||
public Collection<LoanRepaymentPeriodData> retrieveRepaymentSchedule(
|
||||
Long loanId) {
|
||||
|
||||
try {
|
||||
@@ -108,8 +108,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
|
||||
@Override
|
||||
public LoanAccountSummaryData retrieveSummary(MoneyData principal,
|
||||
Collection<LoanRepaymentPeriodDatajpw> repaymentSchedule,
|
||||
Collection<LoanTransactionDatajpw> loanRepayments) {
|
||||
Collection<LoanRepaymentPeriodData> repaymentSchedule,
|
||||
Collection<LoanTransactionDataDTO> loanRepayments) {
|
||||
|
||||
CurrencyData currencyData = new CurrencyData(
|
||||
principal.getCurrencyCode(), principal.getDefaultName(),
|
||||
@@ -128,7 +128,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
BigDecimal totalInArrears = BigDecimal.ZERO;
|
||||
BigDecimal totalWaived = BigDecimal.ZERO;
|
||||
|
||||
for (LoanRepaymentPeriodDatajpw installment : repaymentSchedule) {
|
||||
for (LoanRepaymentPeriodData installment : repaymentSchedule) {
|
||||
originalPrincipal = originalPrincipal.add(installment
|
||||
.getPrincipal().getAmount());
|
||||
principalPaid = principalPaid.add(installment.getPrincipalPaid()
|
||||
@@ -149,12 +149,14 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
totalOutstanding = totalOutstanding.add(installment
|
||||
.getTotalOutstanding().getAmount());
|
||||
|
||||
if (installment.getDate().isBefore(new LocalDate())) {
|
||||
totalInArrears = totalInArrears.add(installment
|
||||
.getTotalOutstanding().getAmount());
|
||||
}
|
||||
}
|
||||
|
||||
totalInArrears = BigDecimal.TEN;
|
||||
|
||||
Long waiverType = (long) 4;
|
||||
for (LoanTransactionDatajpw loanRepayment : loanRepayments) {
|
||||
for (LoanTransactionDataDTO loanRepayment : loanRepayments) {
|
||||
Long transactionType = loanRepayment.getTransactionType().getId();
|
||||
if (transactionType.equals(waiverType)) {
|
||||
totalWaived = totalWaived.add(loanRepayment.getTotal()
|
||||
@@ -176,7 +178,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<LoanTransactionDatajpw> retrieveLoanPayments(Long loanId) {
|
||||
public Collection<LoanTransactionDataDTO> retrieveLoanPayments(Long loanId) {
|
||||
try {
|
||||
context.authenticatedUser();
|
||||
|
||||
@@ -214,7 +216,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
|
||||
boolean undoApprovalAllowed = waitingForDisbursal;
|
||||
|
||||
boolean undoDisbursalAllowed = isActive && (repaymentAndWaiveCount == 0);
|
||||
boolean undoDisbursalAllowed = isActive
|
||||
&& (repaymentAndWaiveCount == 0);
|
||||
|
||||
boolean disbursalAllowed = waitingForDisbursal;
|
||||
|
||||
@@ -524,7 +527,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
}
|
||||
|
||||
private static final class LoanScheduleMapper implements
|
||||
RowMapper<LoanRepaymentPeriodDatajpw> {
|
||||
RowMapper<LoanRepaymentPeriodData> {
|
||||
|
||||
public String loanScheduleSchema() {
|
||||
|
||||
@@ -538,7 +541,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanRepaymentPeriodDatajpw mapRow(final ResultSet rs,
|
||||
public LoanRepaymentPeriodData mapRow(final ResultSet rs,
|
||||
final int rowNum) throws SQLException {
|
||||
|
||||
String currencyCode = rs.getString("currencyCode");
|
||||
@@ -579,7 +582,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
principalBD.add(interestBD).subtract(principalPaidBD)
|
||||
.subtract(interestPaidBD));
|
||||
|
||||
return new LoanRepaymentPeriodDatajpw(loanId, period, date,
|
||||
return new LoanRepaymentPeriodData(loanId, period, date,
|
||||
principal, principalPaid, principalOutstanding, interest,
|
||||
interestPaid, interestOutstanding, total, totalPaid,
|
||||
totalOutstanding);
|
||||
@@ -587,7 +590,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
}
|
||||
|
||||
private static final class LoanPaymentsMapper implements
|
||||
RowMapper<LoanTransactionDatajpw> {
|
||||
RowMapper<LoanTransactionDataDTO> {
|
||||
|
||||
public String LoanPaymentsSchema() {
|
||||
|
||||
@@ -599,7 +602,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanTransactionDatajpw mapRow(final ResultSet rs,
|
||||
public LoanTransactionDataDTO mapRow(final ResultSet rs,
|
||||
final int rowNum) throws SQLException {
|
||||
|
||||
String currencyCode = rs.getString("currencyCode");
|
||||
@@ -622,7 +625,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
BigDecimal totalBD = rs.getBigDecimal("total");
|
||||
MoneyData total = MoneyData.of(currencyData, totalBD);
|
||||
|
||||
return new LoanTransactionDatajpw(id, transactionType, date, total);
|
||||
return new LoanTransactionDataDTO(id, transactionType, date, total);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-376
@@ -1,376 +0,0 @@
|
||||
package org.mifosng.platform.loan.domain;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mifosng.platform.api.data.CurrencyData;
|
||||
import org.mifosng.platform.api.data.DerivedLoanData;
|
||||
import org.mifosng.platform.api.data.LoanTransactionData;
|
||||
import org.mifosng.platform.api.data.LoanRepaymentPeriodData;
|
||||
import org.mifosng.platform.api.data.LoanRepaymentScheduleData;
|
||||
import org.mifosng.platform.api.data.MoneyData;
|
||||
import org.mifosng.platform.currency.domain.MonetaryCurrency;
|
||||
import org.mifosng.platform.currency.domain.Money;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class DerivedLoanDataProcessorTest {
|
||||
|
||||
private DerivedLoanDataProcessor loanDataProcessor = new DerivedLoanDataProcessor();
|
||||
private MonetaryCurrency cfaCurrency = new MonetaryCurrencyBuilder().withCode("XOF").withDigitsAfterDecimal(0).build();
|
||||
private Money arrearsTolerance = new MoneyBuilder().with(cfaCurrency).with("0.0").build();
|
||||
|
||||
@Test
|
||||
public void shouldDeriveLoanRepaymentScheduleWithSingleRepaymentPeriodAndRepaymentInFull() {
|
||||
|
||||
|
||||
|
||||
List<LoanRepaymentScheduleInstallment> repaymentScheduleWithSinglePeriod = new ArrayList<LoanRepaymentScheduleInstallment>();
|
||||
|
||||
LoanRepaymentScheduleInstallment firstRepaymentPeriod = new LoanRepaymentScheduleInstallmentBuilder(cfaCurrency)
|
||||
.withPrincipal("1000")
|
||||
.withInterest("10")
|
||||
.withDueDate(LocalDate.now())
|
||||
.build();
|
||||
repaymentScheduleWithSinglePeriod.add(firstRepaymentPeriod);
|
||||
|
||||
List<LoanTransaction> singleRepaymentInFull = new ArrayList<LoanTransaction>();
|
||||
|
||||
Money fullAmount = new MoneyBuilder().with(cfaCurrency).with("1010").build();
|
||||
|
||||
LoanTransaction fullRepayment = new LoanTransactionBuilder().with(fullAmount).build();
|
||||
singleRepaymentInFull.add(fullRepayment);
|
||||
|
||||
// exercise test
|
||||
DerivedLoanData derivedData = loanDataProcessor.process(repaymentScheduleWithSinglePeriod, singleRepaymentInFull, asCurrencyData(cfaCurrency), arrearsTolerance);
|
||||
|
||||
// verification
|
||||
assertThat(derivedData, is(notNullValue()));
|
||||
|
||||
LoanRepaymentScheduleData repaymentSchedule = derivedData.getRepaymentSchedule();
|
||||
assertThat(repaymentSchedule, is(notNullValue()));
|
||||
|
||||
List<LoanRepaymentPeriodData> periods = repaymentSchedule.getPeriods();
|
||||
assertThat(periods, is(notNullValue()));
|
||||
assertThat(periods.size(), is(1));
|
||||
|
||||
LoanRepaymentPeriodData periodData = periods.get(0);
|
||||
|
||||
MoneyData expectedPrincipal = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("1000").build());
|
||||
MoneyData expectedPrincipalPaid = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("1000").build());
|
||||
MoneyData expectedPrincipalOutstanding = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("0").build());
|
||||
MoneyData expectedInterest = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("10").build());
|
||||
MoneyData expectedInterestPaid = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("10").build());
|
||||
MoneyData expectedInterestOutstanding = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("0").build());
|
||||
|
||||
MoneyData expectedTotal = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("1010").build());
|
||||
|
||||
assertThat(periodData.getPrincipal(), is(expectedPrincipal));
|
||||
assertThat(periodData.getPrincipalPaid(), is(expectedPrincipalPaid));
|
||||
assertThat(periodData.getPrincipalOutstanding(), is(expectedPrincipalOutstanding));
|
||||
|
||||
assertThat(periodData.getInterest(), is(expectedInterest));
|
||||
assertThat(periodData.getInterestPaid(), is(expectedInterestPaid));
|
||||
assertThat(periodData.getInterestOutstanding(), is(expectedInterestOutstanding));
|
||||
|
||||
// assert repayments are ok
|
||||
List<LoanTransactionData> loanRepayments = derivedData.getLoanRepayments();
|
||||
assertThat(loanRepayments, is(notNullValue()));
|
||||
assertThat(loanRepayments.size(), is(1));
|
||||
|
||||
LoanTransactionData firstRepayment = loanRepayments.get(0);
|
||||
assertThat(firstRepayment.getPrincipal(), is(expectedPrincipalPaid));
|
||||
assertThat(firstRepayment.getInterest(), is(expectedInterestPaid));
|
||||
assertThat(firstRepayment.getTotal(), is(expectedTotal));
|
||||
}
|
||||
|
||||
private CurrencyData asCurrencyData(MonetaryCurrency currency) {
|
||||
return new CurrencyData(currency.getCode(), "", currency.getDigitsAfterDecimal(), "CFA", "");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDeriveLoanRepaymentScheduleWithSingleRepaymentPeriodAndPartialRepayment() {
|
||||
|
||||
List<LoanRepaymentScheduleInstallment> repaymentScheduleWithSinglePeriod = new ArrayList<LoanRepaymentScheduleInstallment>();
|
||||
|
||||
LoanRepaymentScheduleInstallment firstRepaymentPeriod = new LoanRepaymentScheduleInstallmentBuilder(cfaCurrency)
|
||||
.withPrincipal("1000")
|
||||
.withInterest("10")
|
||||
.withDueDate(LocalDate.now())
|
||||
.build();
|
||||
repaymentScheduleWithSinglePeriod.add(firstRepaymentPeriod);
|
||||
|
||||
List<LoanTransaction> singlePartialRepayment = new ArrayList<LoanTransaction>();
|
||||
|
||||
Money partialAmount = new MoneyBuilder().with(cfaCurrency).with("510").build();
|
||||
|
||||
LoanTransaction partialRepayment = new LoanTransactionBuilder().with(partialAmount).build();
|
||||
singlePartialRepayment.add(partialRepayment);
|
||||
|
||||
// exercise test
|
||||
DerivedLoanData derivedData = loanDataProcessor.process(repaymentScheduleWithSinglePeriod, singlePartialRepayment, asCurrencyData(cfaCurrency), arrearsTolerance);
|
||||
|
||||
// verification
|
||||
assertThat(derivedData, is(notNullValue()));
|
||||
|
||||
LoanRepaymentScheduleData repaymentSchedule = derivedData.getRepaymentSchedule();
|
||||
assertThat(repaymentSchedule, is(notNullValue()));
|
||||
|
||||
List<LoanRepaymentPeriodData> periods = repaymentSchedule.getPeriods();
|
||||
assertThat(periods, is(notNullValue()));
|
||||
assertThat(periods.size(), is(1));
|
||||
|
||||
LoanRepaymentPeriodData periodData = periods.get(0);
|
||||
|
||||
MoneyData expectedPrincipal = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("1000").build());
|
||||
MoneyData expectedPrincipalPaid = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("500").build());
|
||||
MoneyData expectedPrincipalOutstanding = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("500").build());
|
||||
MoneyData expectedInterest = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("10").build());
|
||||
MoneyData expectedInterestPaid = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("10").build());
|
||||
MoneyData expectedInterestOutstanding = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("0").build());
|
||||
|
||||
MoneyData expectedTotal = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("510").build());
|
||||
|
||||
assertThat(periodData.getPrincipal(), is(expectedPrincipal));
|
||||
assertThat(periodData.getPrincipalPaid(), is(expectedPrincipalPaid));
|
||||
assertThat(periodData.getPrincipalOutstanding(), is(expectedPrincipalOutstanding));
|
||||
|
||||
assertThat(periodData.getInterest(), is(expectedInterest));
|
||||
assertThat(periodData.getInterestPaid(), is(expectedInterestPaid));
|
||||
assertThat(periodData.getInterestOutstanding(), is(expectedInterestOutstanding));
|
||||
|
||||
// assert repayments are ok
|
||||
List<LoanTransactionData> loanRepayments = derivedData.getLoanRepayments();
|
||||
assertThat(loanRepayments, is(notNullValue()));
|
||||
assertThat(loanRepayments.size(), is(1));
|
||||
|
||||
LoanTransactionData firstRepayment = loanRepayments.get(0);
|
||||
assertThat(firstRepayment.getPrincipal(), is(expectedPrincipalPaid));
|
||||
assertThat(firstRepayment.getInterest(), is(expectedInterestPaid));
|
||||
assertThat(firstRepayment.getTotal(), is(expectedTotal));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void shouldDeriveLoanRepaymentScheduleWithSingleRepaymentPeriodAndPartialRepaymentLessThanInterestComponent() {
|
||||
|
||||
List<LoanRepaymentScheduleInstallment> repaymentScheduleWithSinglePeriod = new ArrayList<LoanRepaymentScheduleInstallment>();
|
||||
|
||||
LoanRepaymentScheduleInstallment firstRepaymentPeriod = new LoanRepaymentScheduleInstallmentBuilder(cfaCurrency)
|
||||
.withPrincipal("1000")
|
||||
.withInterest("10")
|
||||
.withDueDate(LocalDate.now())
|
||||
.build();
|
||||
repaymentScheduleWithSinglePeriod.add(firstRepaymentPeriod);
|
||||
|
||||
List<LoanTransaction> singlePartialRepayment = new ArrayList<LoanTransaction>();
|
||||
|
||||
Money partialAmount = new MoneyBuilder().with(cfaCurrency).with("5").build();
|
||||
|
||||
LoanTransaction partialRepayment = new LoanTransactionBuilder().with(partialAmount).build();
|
||||
singlePartialRepayment.add(partialRepayment);
|
||||
|
||||
// exercise test
|
||||
DerivedLoanData derivedData = loanDataProcessor.process(repaymentScheduleWithSinglePeriod, singlePartialRepayment, asCurrencyData(cfaCurrency), arrearsTolerance);
|
||||
|
||||
// verification
|
||||
assertThat(derivedData, is(notNullValue()));
|
||||
|
||||
LoanRepaymentScheduleData repaymentSchedule = derivedData.getRepaymentSchedule();
|
||||
assertThat(repaymentSchedule, is(notNullValue()));
|
||||
|
||||
List<LoanRepaymentPeriodData> periods = repaymentSchedule.getPeriods();
|
||||
assertThat(periods, is(notNullValue()));
|
||||
assertThat(periods.size(), is(1));
|
||||
|
||||
LoanRepaymentPeriodData periodData = periods.get(0);
|
||||
|
||||
MoneyData expectedPrincipal = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("1000").build());
|
||||
MoneyData expectedPrincipalPaid = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("0").build());
|
||||
MoneyData expectedPrincipalOutstanding = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("1000").build());
|
||||
MoneyData expectedInterest = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("10").build());
|
||||
MoneyData expectedInterestPaid = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("5").build());
|
||||
MoneyData expectedInterestOutstanding = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("5").build());
|
||||
|
||||
MoneyData expectedTotal = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("5").build());
|
||||
|
||||
assertThat(periodData.getPrincipal(), is(expectedPrincipal));
|
||||
assertThat(periodData.getPrincipalPaid(), is(expectedPrincipalPaid));
|
||||
assertThat(periodData.getPrincipalOutstanding(), is(expectedPrincipalOutstanding));
|
||||
|
||||
assertThat(periodData.getInterest(), is(expectedInterest));
|
||||
assertThat(periodData.getInterestPaid(), is(expectedInterestPaid));
|
||||
assertThat(periodData.getInterestOutstanding(), is(expectedInterestOutstanding));
|
||||
|
||||
// assert repayments are ok
|
||||
List<LoanTransactionData> loanRepayments = derivedData.getLoanRepayments();
|
||||
assertThat(loanRepayments, is(notNullValue()));
|
||||
assertThat(loanRepayments.size(), is(1));
|
||||
|
||||
LoanTransactionData firstRepayment = loanRepayments.get(0);
|
||||
assertThat(firstRepayment.getPrincipal(), is(expectedPrincipalPaid));
|
||||
assertThat(firstRepayment.getInterest(), is(expectedInterestPaid));
|
||||
assertThat(firstRepayment.getTotal(), is(expectedTotal));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDeriveLoanRepaymentScheduleWithSingleRepaymentPeriodAndOverPayment() {
|
||||
|
||||
List<LoanRepaymentScheduleInstallment> repaymentScheduleWithSinglePeriod = new ArrayList<LoanRepaymentScheduleInstallment>();
|
||||
|
||||
LoanRepaymentScheduleInstallment firstRepaymentPeriod = new LoanRepaymentScheduleInstallmentBuilder(cfaCurrency)
|
||||
.withPrincipal("1000")
|
||||
.withInterest("10")
|
||||
.withDueDate(LocalDate.now())
|
||||
.build();
|
||||
repaymentScheduleWithSinglePeriod.add(firstRepaymentPeriod);
|
||||
|
||||
List<LoanTransaction> singleOverRepayment = new ArrayList<LoanTransaction>();
|
||||
|
||||
Money partialAmount = new MoneyBuilder().with(cfaCurrency).with("1200").build();
|
||||
|
||||
LoanTransaction overRepayment = new LoanTransactionBuilder().with(partialAmount).build();
|
||||
singleOverRepayment.add(overRepayment);
|
||||
|
||||
// exercise test
|
||||
DerivedLoanData derivedData = loanDataProcessor.process(repaymentScheduleWithSinglePeriod, singleOverRepayment, asCurrencyData(cfaCurrency), arrearsTolerance);
|
||||
|
||||
// verification
|
||||
assertThat(derivedData, is(notNullValue()));
|
||||
|
||||
LoanRepaymentScheduleData repaymentSchedule = derivedData.getRepaymentSchedule();
|
||||
assertThat(repaymentSchedule, is(notNullValue()));
|
||||
|
||||
List<LoanRepaymentPeriodData> periods = repaymentSchedule.getPeriods();
|
||||
assertThat(periods, is(notNullValue()));
|
||||
assertThat(periods.size(), is(1));
|
||||
|
||||
LoanRepaymentPeriodData periodData = periods.get(0);
|
||||
|
||||
MoneyData expectedPrincipal = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("1000").build());
|
||||
MoneyData expectedPrincipalPaid = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("1000").build());
|
||||
MoneyData expectedPrincipalOutstanding = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("0").build());
|
||||
MoneyData expectedInterest = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("10").build());
|
||||
MoneyData expectedInterestPaid = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("10").build());
|
||||
MoneyData expectedInterestOutstanding = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("0").build());
|
||||
|
||||
MoneyData expectedTotal = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("1010").build());
|
||||
MoneyData expectedOverpayment = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("190").build());
|
||||
|
||||
assertThat(periodData.getPrincipal(), is(expectedPrincipal));
|
||||
assertThat(periodData.getPrincipalPaid(), is(expectedPrincipalPaid));
|
||||
assertThat(periodData.getPrincipalOutstanding(), is(expectedPrincipalOutstanding));
|
||||
|
||||
assertThat(periodData.getInterest(), is(expectedInterest));
|
||||
assertThat(periodData.getInterestPaid(), is(expectedInterestPaid));
|
||||
assertThat(periodData.getInterestOutstanding(), is(expectedInterestOutstanding));
|
||||
|
||||
// assert repayments are ok
|
||||
List<LoanTransactionData> loanRepayments = derivedData.getLoanRepayments();
|
||||
assertThat(loanRepayments, is(notNullValue()));
|
||||
assertThat(loanRepayments.size(), is(1));
|
||||
|
||||
LoanTransactionData firstRepayment = loanRepayments.get(0);
|
||||
assertThat(firstRepayment.getPrincipal(), is(expectedPrincipalPaid));
|
||||
assertThat(firstRepayment.getInterest(), is(expectedInterestPaid));
|
||||
assertThat(firstRepayment.getTotal(), is(expectedTotal));
|
||||
assertThat(firstRepayment.getOverpaid(), is(expectedOverpayment));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDeriveLoanRepaymentScheduleWithTwoRepaymentPeriodAndOneSinglePayment() {
|
||||
|
||||
List<LoanRepaymentScheduleInstallment> repaymentScheduleWithSinglePeriod = new ArrayList<LoanRepaymentScheduleInstallment>();
|
||||
|
||||
LoanRepaymentScheduleInstallment firstRepaymentPeriod = new LoanRepaymentScheduleInstallmentBuilder(cfaCurrency)
|
||||
.withPrincipal("1000")
|
||||
.withInterest("10")
|
||||
.withDueDate(LocalDate.now())
|
||||
.build();
|
||||
|
||||
LoanRepaymentScheduleInstallment secondRepaymentPeriod = new LoanRepaymentScheduleInstallmentBuilder(cfaCurrency)
|
||||
.withPrincipal("1000")
|
||||
.withInterest("10")
|
||||
.withDueDate(LocalDate.now().plusWeeks(1))
|
||||
.build();
|
||||
|
||||
repaymentScheduleWithSinglePeriod.add(firstRepaymentPeriod);
|
||||
repaymentScheduleWithSinglePeriod.add(secondRepaymentPeriod);
|
||||
|
||||
List<LoanTransaction> singleRepayment = new ArrayList<LoanTransaction>();
|
||||
|
||||
Money partialAmount = new MoneyBuilder().with(cfaCurrency).with("1200").build();
|
||||
|
||||
LoanTransaction overRepaymentForFirstPeriod = new LoanTransactionBuilder().with(partialAmount).build();
|
||||
singleRepayment.add(overRepaymentForFirstPeriod);
|
||||
|
||||
// exercise test
|
||||
DerivedLoanData derivedData = loanDataProcessor.process(repaymentScheduleWithSinglePeriod, singleRepayment, asCurrencyData(cfaCurrency), arrearsTolerance);
|
||||
|
||||
// verification
|
||||
assertThat(derivedData, is(notNullValue()));
|
||||
|
||||
LoanRepaymentScheduleData repaymentSchedule = derivedData.getRepaymentSchedule();
|
||||
assertThat(repaymentSchedule, is(notNullValue()));
|
||||
|
||||
List<LoanRepaymentPeriodData> periods = repaymentSchedule.getPeriods();
|
||||
assertThat(periods, is(notNullValue()));
|
||||
assertThat(periods.size(), is(2));
|
||||
|
||||
LoanRepaymentPeriodData firstPeriod = periods.get(0);
|
||||
|
||||
MoneyData expectedPrincipal = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("1000").build());
|
||||
MoneyData expectedPrincipalPaid = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("1000").build());
|
||||
MoneyData expectedPrincipalOutstanding = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("0").build());
|
||||
MoneyData expectedInterest = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("10").build());
|
||||
MoneyData expectedInterestPaid = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("10").build());
|
||||
MoneyData expectedInterestOutstanding = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("0").build());
|
||||
|
||||
assertThat(firstPeriod.getPrincipal(), is(expectedPrincipal));
|
||||
assertThat(firstPeriod.getPrincipalPaid(), is(expectedPrincipalPaid));
|
||||
assertThat(firstPeriod.getPrincipalOutstanding(), is(expectedPrincipalOutstanding));
|
||||
|
||||
assertThat(firstPeriod.getInterest(), is(expectedInterest));
|
||||
assertThat(firstPeriod.getInterestPaid(), is(expectedInterestPaid));
|
||||
assertThat(firstPeriod.getInterestOutstanding(), is(expectedInterestOutstanding));
|
||||
|
||||
LoanRepaymentPeriodData secondPeriod = periods.get(1);
|
||||
|
||||
expectedPrincipal = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("1000").build());
|
||||
expectedPrincipalPaid = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("180").build());
|
||||
expectedPrincipalOutstanding = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("820").build());
|
||||
expectedInterest = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("10").build());
|
||||
expectedInterestPaid = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("10").build());
|
||||
expectedInterestOutstanding = moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("0").build());
|
||||
|
||||
assertThat(secondPeriod.getPrincipal(), is(expectedPrincipal));
|
||||
assertThat(secondPeriod.getPrincipalPaid(), is(expectedPrincipalPaid));
|
||||
assertThat(secondPeriod.getPrincipalOutstanding(), is(expectedPrincipalOutstanding));
|
||||
|
||||
assertThat(secondPeriod.getInterest(), is(expectedInterest));
|
||||
assertThat(secondPeriod.getInterestPaid(), is(expectedInterestPaid));
|
||||
assertThat(secondPeriod.getInterestOutstanding(), is(expectedInterestOutstanding));
|
||||
|
||||
// assert repayments are ok
|
||||
List<LoanTransactionData> loanRepayments = derivedData.getLoanRepayments();
|
||||
assertThat(loanRepayments, is(notNullValue()));
|
||||
assertThat(loanRepayments.size(), is(1));
|
||||
|
||||
LoanTransactionData firstRepayment = loanRepayments.get(0);
|
||||
assertThat(firstRepayment.getPrincipal(), is(moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("1180").build())));
|
||||
assertThat(firstRepayment.getInterest(), is(moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("20").build())));
|
||||
assertThat(firstRepayment.getTotal(), is(moneyDataFrom(new MoneyBuilder().with(cfaCurrency).with("1200").build())));
|
||||
}
|
||||
|
||||
private MoneyData moneyDataFrom(Money money) {
|
||||
CurrencyData currency = new CurrencyData(money.getCurrencyCode(), "", money.getCurrencyDigitsAfterDecimal(), "CFA", "");
|
||||
return MoneyData.of(currency, money.getAmount());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user