mifosx-58: restructure loan schedule to contain summary plus detail of schedule. As part of this work I removed the use of MoneyData in data objects and instead return currency and decimal for each monetary amount aligning with rest of application.

This commit is contained in:
Keith Woodlock
2012-09-14 16:10:16 +01:00
parent 4717393816
commit e4f8eb6b12
8 changed files with 209 additions and 564 deletions
@@ -32,14 +32,14 @@ import org.mifosng.platform.api.data.EntityIdentifier;
import org.mifosng.platform.api.data.EnumOptionData; import org.mifosng.platform.api.data.EnumOptionData;
import org.mifosng.platform.api.data.FundData; import org.mifosng.platform.api.data.FundData;
import org.mifosng.platform.api.data.LoanAccountData; 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.LoanBasicDetailsData;
import org.mifosng.platform.api.data.LoanPermissionData; import org.mifosng.platform.api.data.LoanPermissionData;
import org.mifosng.platform.api.data.LoanProductLookup; import org.mifosng.platform.api.data.LoanProductLookup;
import org.mifosng.platform.api.data.LoanRepaymentPeriodData;
import org.mifosng.platform.api.data.LoanRepaymentTransactionData; import org.mifosng.platform.api.data.LoanRepaymentTransactionData;
import org.mifosng.platform.api.data.LoanSchedule; import org.mifosng.platform.api.data.LoanSchedule;
import org.mifosng.platform.api.data.LoanScheduleData;
import org.mifosng.platform.api.data.LoanTransactionData; import org.mifosng.platform.api.data.LoanTransactionData;
import org.mifosng.platform.api.data.MoneyData;
import org.mifosng.platform.api.data.StaffData; import org.mifosng.platform.api.data.StaffData;
import org.mifosng.platform.api.data.TransactionProcessingStrategyData; import org.mifosng.platform.api.data.TransactionProcessingStrategyData;
import org.mifosng.platform.api.infrastructure.ApiDataConversionService; import org.mifosng.platform.api.infrastructure.ApiDataConversionService;
@@ -159,7 +159,7 @@ public class LoansApiResource {
// populate loan officers if query param is passed in // populate loan officers if query param is passed in
Collection<StaffData> allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(loanBasicDetails.getClientOfficeId()); Collection<StaffData> allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(loanBasicDetails.getClientOfficeId());
final LoanAccountData newLoanAccount = new LoanAccountData(loanBasicDetails, convenienceDataRequired, null, null, null, null, charges, final LoanAccountData newLoanAccount = new LoanAccountData(loanBasicDetails, convenienceDataRequired, null, null, null, charges,
productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions, productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions,
repaymentStrategyOptions, interestRateFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions,
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers); amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers);
@@ -196,16 +196,15 @@ public class LoansApiResource {
int loanRepaymentsCount = 0; int loanRepaymentsCount = 0;
Collection<LoanRepaymentTransactionData> loanRepayments = null; Collection<LoanRepaymentTransactionData> loanRepayments = null;
Collection<LoanRepaymentPeriodData> repaymentSchedule = null; LoanScheduleData repaymentSchedule = null;
LoanAccountSummaryData summary = null;
LoanPermissionData permissions = null; LoanPermissionData permissions = null;
Collection<ChargeData> charges = null; Collection<ChargeData> charges = null;
boolean convenienceDataRequired = false; boolean convenienceDataRequired = false;
Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters()); final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
if (!associationParameters.isEmpty()) { if (!associationParameters.isEmpty()) {
if (associationParameters.contains("all")) { if (associationParameters.contains("all")) {
responseParameters.addAll(Arrays.asList("summary", "repaymentSchedule", "loanRepayments", "permissions", "convenienceData", "charges")); responseParameters.addAll(Arrays.asList("repaymentSchedule", "loanRepayments", "permissions", "convenienceData", "charges"));
} else { } else {
responseParameters.addAll(associationParameters); responseParameters.addAll(associationParameters);
} }
@@ -215,11 +214,12 @@ public class LoansApiResource {
loanRepayments = currentLoanRepayments; loanRepayments = currentLoanRepayments;
loanRepaymentsCount = loanRepayments.size(); loanRepaymentsCount = loanRepayments.size();
} }
repaymentSchedule = this.loanReadPlatformService.retrieveRepaymentSchedule(loanId); repaymentSchedule = this.loanReadPlatformService.retrieveRepaymentSchedule(loanId, loanBasicDetails.getCurrency(), loanRepayments);
summary = this.loanReadPlatformService.retrieveSummary(loanBasicDetails.getCurrency(), repaymentSchedule, loanRepayments); MoneyData tolerance = MoneyData.of(loanBasicDetails.getCurrency(), loanBasicDetails.getInArrearsTolerance());
MoneyData totalOutstandingMoney = MoneyData.of(loanBasicDetails.getCurrency(), repaymentSchedule.totalOutstanding());
boolean isWaiveAllowed = summary.isWaiveAllowed(loanBasicDetails.getCurrency(), loanBasicDetails.getInArrearsTolerance()); boolean isWaiveAllowed = totalOutstandingMoney.isGreaterThanZero() && (tolerance.isGreaterThan(totalOutstandingMoney) || tolerance.isEqualTo(totalOutstandingMoney));
permissions = this.loanReadPlatformService.retrieveLoanPermissions(loanBasicDetails, isWaiveAllowed, loanRepaymentsCount); permissions = this.loanReadPlatformService.retrieveLoanPermissions(loanBasicDetails, isWaiveAllowed, loanRepaymentsCount);
convenienceDataRequired = true; convenienceDataRequired = true;
@@ -270,7 +270,8 @@ public class LoansApiResource {
chargeTemplate = this.chargeReadPlatformService.retrieveLoanChargeTemplate(); chargeTemplate = this.chargeReadPlatformService.retrieveLoanChargeTemplate();
} }
final LoanAccountData loanAccount = new LoanAccountData(loanBasicDetails, convenienceDataRequired, summary, repaymentSchedule, loanRepayments, permissions, charges, final LoanAccountData loanAccount = new LoanAccountData(loanBasicDetails, convenienceDataRequired,
repaymentSchedule, loanRepayments, permissions, charges,
productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions, productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions,
repaymentStrategyOptions, interestRateFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions,
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers); amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers);
@@ -8,8 +8,10 @@ import org.joda.time.LocalDate;
/** /**
* Immutable data object representing loan account data. * Immutable data object representing loan account data.
*/ */
@SuppressWarnings("unused")
public class LoanAccountData { public class LoanAccountData {
// basic loan details
private final Long id; private final Long id;
private final String externalId; private final String externalId;
private final Long clientId; private final Long clientId;
@@ -50,15 +52,13 @@ public class LoanAccountData {
private final LocalDate lifeCycleStatusDate; private final LocalDate lifeCycleStatusDate;
// associations // associations
private final LoanAccountSummaryData summary; private final LoanScheduleData repaymentSchedule;
private final Collection<LoanRepaymentPeriodData> repaymentSchedule;
private final Collection<LoanRepaymentTransactionData> loanRepayments; private final Collection<LoanRepaymentTransactionData> loanRepayments;
private final Collection<ChargeData> charges; private final Collection<ChargeData> charges;
private final LoanPermissionData permissions; private final LoanPermissionData permissions;
private final LoanConvenienceData convenienceData; private final LoanConvenienceData convenienceData;
// template // template
@SuppressWarnings("unused")
private final Collection<StaffData> loanOfficerOptions; private final Collection<StaffData> loanOfficerOptions;
private final Collection<LoanProductLookup> productOptions; private final Collection<LoanProductLookup> productOptions;
private final Collection<EnumOptionData> termFrequencyTypeOptions; private final Collection<EnumOptionData> termFrequencyTypeOptions;
@@ -70,14 +70,12 @@ public class LoanAccountData {
private final Collection<EnumOptionData> interestCalculationPeriodTypeOptions; private final Collection<EnumOptionData> interestCalculationPeriodTypeOptions;
private final Collection<FundData> fundOptions; private final Collection<FundData> fundOptions;
private final Collection<ChargeData> chargeOptions; private final Collection<ChargeData> chargeOptions;
@SuppressWarnings("unused")
private final ChargeData chargeTemplate; private final ChargeData chargeTemplate;
public LoanAccountData( public LoanAccountData(
final LoanBasicDetailsData basicDetails, final LoanBasicDetailsData basicDetails,
final boolean convenienceDataRequired, final boolean convenienceDataRequired,
final LoanAccountSummaryData summary, final LoanScheduleData repaymentSchedule,
final Collection<LoanRepaymentPeriodData> repaymentSchedule,
final Collection<LoanRepaymentTransactionData> loanRepayments, final Collection<LoanRepaymentTransactionData> loanRepayments,
final LoanPermissionData permissions, final LoanPermissionData permissions,
final Collection<ChargeData> charges, final Collection<ChargeData> charges,
@@ -93,7 +91,6 @@ public class LoanAccountData {
final Collection<ChargeData> chargeOptions, final Collection<ChargeData> chargeOptions,
final ChargeData chargeTemplate, final ChargeData chargeTemplate,
final Collection<StaffData> loanOfficerOptions) { final Collection<StaffData> loanOfficerOptions) {
this.summary = summary;
this.repaymentSchedule = repaymentSchedule; this.repaymentSchedule = repaymentSchedule;
this.loanRepayments = loanRepayments; this.loanRepayments = loanRepayments;
this.permissions = permissions; this.permissions = permissions;
@@ -177,212 +174,4 @@ public class LoanAccountData {
this.status = basicDetails.getStatus(); this.status = basicDetails.getStatus();
this.lifeCycleStatusDate = basicDetails.getLifeCycleStatusDate(); this.lifeCycleStatusDate = basicDetails.getLifeCycleStatusDate();
} }
public Long getId() {
return id;
}
public String getExternalId() {
return externalId;
}
public Long getClientId() {
return clientId;
}
public String getClientName() {
return clientName;
}
public Long getLoanProductId() {
return loanProductId;
}
public String getLoanProductName() {
return loanProductName;
}
public String getLoanProductDescription() {
return loanProductDescription;
}
public EnumOptionData getStatus() {
return status;
}
public Long getFundId() {
return fundId;
}
public String getFundName() {
return fundName;
}
public LocalDate getSubmittedOnDate() {
return submittedOnDate;
}
public LocalDate getApprovedOnDate() {
return approvedOnDate;
}
public LocalDate getExpectedDisbursementDate() {
return expectedDisbursementDate;
}
public LocalDate getActualDisbursementDate() {
return actualDisbursementDate;
}
public LocalDate getRepaymentsStartingFromDate() {
return repaymentsStartingFromDate;
}
public LocalDate getInterestChargedFromDate() {
return interestChargedFromDate;
}
public LocalDate getClosedOnDate() {
return closedOnDate;
}
public LocalDate getExpectedMaturityDate() {
return expectedMaturityDate;
}
public CurrencyData getCurrency() {
return currency;
}
public BigDecimal getPrincipal() {
return this.principal;
}
public BigDecimal getInArrearsTolerance() {
return this.inArrearsTolerance;
}
public Integer getTermFrequency() {
return termFrequency;
}
public EnumOptionData getTermPeriodFrequencyType() {
return termPeriodFrequencyType;
}
public Integer getNumberOfRepayments() {
return numberOfRepayments;
}
public Integer getRepaymentEvery() {
return repaymentEvery;
}
public Integer getTransactionStrategyId() {
return transactionStrategyId;
}
public BigDecimal getInterestRatePerPeriod() {
return interestRatePerPeriod;
}
public BigDecimal getAnnualInterestRate() {
return annualInterestRate;
}
public EnumOptionData getRepaymentFrequencyType() {
return repaymentFrequencyType;
}
public EnumOptionData getInterestRateFrequencyType() {
return interestRateFrequencyType;
}
public EnumOptionData getAmortizationType() {
return amortizationType;
}
public EnumOptionData getInterestType() {
return interestType;
}
public EnumOptionData getInterestCalculationPeriodType() {
return interestCalculationPeriodType;
}
public LocalDate getLifeCycleStatusDate() {
return lifeCycleStatusDate;
}
public LoanAccountSummaryData getSummary() {
return summary;
}
public Collection<LoanRepaymentPeriodData> getRepaymentSchedule() {
return repaymentSchedule;
}
public Collection<LoanRepaymentTransactionData> getLoanRepayments() {
return loanRepayments;
}
public LoanPermissionData getPermissions() {
return permissions;
}
public LoanConvenienceData getConvenienceData() {
return convenienceData;
}
public Collection<ChargeData> getCharges() {
return this.charges;
}
public Collection<LoanProductLookup> getProductOptions() {
return productOptions;
}
public Collection<EnumOptionData> getTermFrequencyTypeOptions() {
return termFrequencyTypeOptions;
}
public Collection<EnumOptionData> getRepaymentFrequencyTypeOptions() {
return repaymentFrequencyTypeOptions;
}
public Collection<TransactionProcessingStrategyData> getRepaymentStrategyOptions() {
return repaymentStrategyOptions;
}
public Collection<EnumOptionData> getInterestRateFrequencyTypeOptions() {
return interestRateFrequencyTypeOptions;
}
public Collection<EnumOptionData> getAmortizationTypeOptions() {
return amortizationTypeOptions;
}
public Collection<EnumOptionData> getInterestTypeOptions() {
return interestTypeOptions;
}
public Collection<EnumOptionData> getInterestCalculationPeriodTypeOptions() {
return interestCalculationPeriodTypeOptions;
}
public Collection<FundData> getFundOptions() {
return fundOptions;
}
public Collection<ChargeData> getChargeOptions() {
return chargeOptions;
}
public Long getLoanOfficerId() {
return loanOfficerId;
}
public String getLoanOfficerName() {
return loanOfficerName;
}
} }
@@ -2,38 +2,45 @@ package org.mifosng.platform.api.data;
import java.math.BigDecimal; import java.math.BigDecimal;
/**
* Immutable data object representing summary information of loan.
*
* <code>currency</code> is provided in summary even though its also passed with basic loan information so its possible to just request summary only.
*
* Note: getter/setter not added on purpose - google-gson only requires fields to generate json.
*/
@SuppressWarnings("unused")
public class LoanAccountSummaryData { public class LoanAccountSummaryData {
private MoneyData originalPrincipal; private final CurrencyData currency;
private MoneyData originalInterest; private final BigDecimal originalPrincipal;
private MoneyData originalTotal; private final BigDecimal originalInterest;
private MoneyData principalPaid; private final BigDecimal originalTotal;
private MoneyData principalOutstanding; private final BigDecimal principalPaid;
private MoneyData interestPaid; private final BigDecimal principalOutstanding;
private MoneyData interestWaived; private final BigDecimal interestPaid;
private MoneyData interestOutstanding; private final BigDecimal interestWaived;
private MoneyData totalPaid; private final BigDecimal interestOutstanding;
private MoneyData totalWaived; private final BigDecimal totalPaid;
private MoneyData totalOutstanding; private final BigDecimal totalWaived;
private MoneyData totalInArrears; private final BigDecimal totalOutstanding;
private final BigDecimal totalInArrears;
protected LoanAccountSummaryData() {
//
}
public LoanAccountSummaryData( public LoanAccountSummaryData(
MoneyData originalPrincipal, final CurrencyData currency,
MoneyData principalPaid, final BigDecimal originalPrincipal,
MoneyData principalOutstanding, final BigDecimal principalPaid,
MoneyData originalInterest, final BigDecimal principalOutstanding,
MoneyData interestPaid, final BigDecimal originalInterest,
MoneyData interestWaived, final BigDecimal interestPaid,
MoneyData interestOutstanding, final BigDecimal interestWaived,
MoneyData originalTotal, final BigDecimal interestOutstanding,
MoneyData totalPaid, final BigDecimal originalTotal,
MoneyData totalWaived, final BigDecimal totalPaid,
MoneyData totalOutstanding, final BigDecimal totalWaived,
MoneyData totalInArrears) { final BigDecimal totalOutstanding,
final BigDecimal totalInArrears) {
this.currency = currency;
this.originalPrincipal = originalPrincipal; this.originalPrincipal = originalPrincipal;
this.principalPaid = principalPaid; this.principalPaid = principalPaid;
this.principalOutstanding = principalOutstanding; this.principalOutstanding = principalOutstanding;
@@ -48,104 +55,7 @@ public class LoanAccountSummaryData {
this.totalInArrears = totalInArrears; this.totalInArrears = totalInArrears;
} }
public boolean isWaiveAllowed(final CurrencyData currency, final BigDecimal toleranceAmount) { public BigDecimal totalOutstanding() {
MoneyData tolerance = MoneyData.of(currency, toleranceAmount); return this.totalOutstanding;
return this.totalOutstanding.isGreaterThanZero() && (tolerance.isGreaterThan(this.totalOutstanding) || tolerance.isEqualTo(this.totalOutstanding));
}
public MoneyData getOriginalPrincipal() {
return originalPrincipal;
}
public void setOriginalPrincipal(MoneyData originalPrincipal) {
this.originalPrincipal = originalPrincipal;
}
public MoneyData getOriginalInterest() {
return originalInterest;
}
public void setOriginalInterest(MoneyData originalInterest) {
this.originalInterest = originalInterest;
}
public MoneyData getOriginalTotal() {
return originalTotal;
}
public void setOriginalTotal(MoneyData originalTotal) {
this.originalTotal = originalTotal;
}
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 getInterestPaid() {
return interestPaid;
}
public void setInterestPaid(MoneyData interestPaid) {
this.interestPaid = interestPaid;
}
public MoneyData getInterestWaived() {
return interestWaived;
}
public void setInterestWaived(MoneyData interestWaived) {
this.interestWaived = interestWaived;
}
public MoneyData getInterestOutstanding() {
return interestOutstanding;
}
public void setInterestOutstanding(MoneyData interestOutstanding) {
this.interestOutstanding = interestOutstanding;
}
public MoneyData getTotalPaid() {
return totalPaid;
}
public void setTotalPaid(MoneyData totalPaid) {
this.totalPaid = totalPaid;
}
public MoneyData getTotalWaived() {
return totalWaived;
}
public void setTotalWaived(MoneyData totalWaived) {
this.totalWaived = totalWaived;
}
public MoneyData getTotalOutstanding() {
return totalOutstanding;
}
public void setTotalOutstanding(MoneyData totalOutstanding) {
this.totalOutstanding = totalOutstanding;
}
public MoneyData getTotalInArrears() {
return totalInArrears;
}
public void setTotalInArrears(MoneyData totalInArrears) {
this.totalInArrears = totalInArrears;
} }
} }
@@ -1,33 +1,36 @@
package org.mifosng.platform.api.data; package org.mifosng.platform.api.data;
import java.math.BigDecimal;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
/**
* Immutable data object representing a repayment period of a loan schedule.
*/
public class LoanRepaymentPeriodData { public class LoanRepaymentPeriodData {
private Long loanId; @SuppressWarnings("unused")
private Integer period; private final Long loanId;
private LocalDate date; @SuppressWarnings("unused")
private MoneyData principal; private final Integer period;
private MoneyData principalPaid; private final LocalDate date;
private MoneyData principalOutstanding; private final BigDecimal principal;
private MoneyData interest; private final BigDecimal principalPaid;
private MoneyData interestPaid; private final BigDecimal principalOutstanding;
private MoneyData interestWaived; private final BigDecimal interest;
private MoneyData interestOutstanding; private final BigDecimal interestPaid;
private MoneyData total; private final BigDecimal interestWaived;
private MoneyData totalPaid; private final BigDecimal interestOutstanding;
private MoneyData totalWaived; private final BigDecimal total;
private MoneyData totalOutstanding; private final BigDecimal totalPaid;
private final BigDecimal totalWaived;
private final BigDecimal totalOutstanding;
public LoanRepaymentPeriodData() { public LoanRepaymentPeriodData(final Long loanId, final Integer period,
// final LocalDate date, final BigDecimal principal, final BigDecimal principalPaid,
} final BigDecimal principalOutstanding, final BigDecimal interest,
final BigDecimal interestPaid, final BigDecimal interestWaived, final BigDecimal interestOutstanding,
public LoanRepaymentPeriodData(Long loanId, Integer period, final BigDecimal total, final BigDecimal totalPaid, final BigDecimal totalWaived, final BigDecimal totalOutstanding) {
LocalDate date, MoneyData principal, MoneyData principalPaid,
MoneyData principalOutstanding, MoneyData interest,
MoneyData interestPaid, MoneyData interestWaived, MoneyData interestOutstanding,
MoneyData total, MoneyData totalPaid, MoneyData totalWaived, MoneyData totalOutstanding) {
this.loanId = loanId; this.loanId = loanId;
this.period = period; this.period = period;
this.date = date; this.date = date;
@@ -44,116 +47,51 @@ public class LoanRepaymentPeriodData {
this.totalOutstanding = totalOutstanding; 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() { public LocalDate getDate() {
return date; return date;
} }
public void setDate(LocalDate date) { public BigDecimal getPrincipal() {
this.date = date;
}
public MoneyData getPrincipal() {
return principal; return principal;
} }
public void setPrincipal(MoneyData principal) { public BigDecimal getPrincipalPaid() {
this.principal = principal;
}
public MoneyData getPrincipalPaid() {
return principalPaid; return principalPaid;
} }
public void setPrincipalPaid(MoneyData principalPaid) { public BigDecimal getPrincipalOutstanding() {
this.principalPaid = principalPaid;
}
public MoneyData getPrincipalOutstanding() {
return principalOutstanding; return principalOutstanding;
} }
public void setPrincipalOutstanding(MoneyData principalOutstanding) { public BigDecimal getInterest() {
this.principalOutstanding = principalOutstanding;
}
public MoneyData getInterest() {
return interest; return interest;
} }
public void setInterest(MoneyData interest) { public BigDecimal getInterestPaid() {
this.interest = interest;
}
public MoneyData getInterestPaid() {
return interestPaid; return interestPaid;
} }
public void setInterestPaid(MoneyData interestPaid) { public BigDecimal getInterestWaived() {
this.interestPaid = interestPaid;
}
public MoneyData getInterestWaived() {
return interestWaived; return interestWaived;
} }
public void setInterestWaived(MoneyData interestWaived) { public BigDecimal getInterestOutstanding() {
this.interestWaived = interestWaived;
}
public MoneyData getInterestOutstanding() {
return interestOutstanding; return interestOutstanding;
} }
public void setInterestOutstanding(MoneyData interestOutstanding) { public BigDecimal getTotal() {
this.interestOutstanding = interestOutstanding;
}
public MoneyData getTotal() {
return total; return total;
} }
public void setTotal(MoneyData total) { public BigDecimal getTotalPaid() {
this.total = total;
}
public MoneyData getTotalPaid() {
return totalPaid; return totalPaid;
} }
public void setTotalPaid(MoneyData totalPaid) { public BigDecimal getTotalWaived() {
this.totalPaid = totalPaid;
}
public MoneyData getTotalWaived() {
return totalWaived; return totalWaived;
} }
public void setTotalWaived(MoneyData totalWaived) { public BigDecimal getTotalOutstanding() {
this.totalWaived = totalWaived;
}
public MoneyData getTotalOutstanding() {
return totalOutstanding; return totalOutstanding;
} }
public void setTotalOutstanding(MoneyData totalOutstanding) {
this.totalOutstanding = totalOutstanding;
}
} }
@@ -0,0 +1,94 @@
package org.mifosng.platform.api.data;
import java.math.BigDecimal;
import java.util.Collection;
import org.joda.time.LocalDate;
/**
* Immutable data object representing the expected disbursement and repayment schedule for the loan.
*/
public class LoanScheduleData {
private final LoanAccountSummaryData summary;
@SuppressWarnings("unused")
private final CurrencyData currency;
@SuppressWarnings("unused")
private final Collection<LoanRepaymentPeriodData> repaymentPeriods;
public LoanScheduleData(final CurrencyData currency, final Collection<LoanRepaymentPeriodData> repaymentPeriods, final Collection<LoanRepaymentTransactionData> loanRepayments) {
this.summary = derivedSummaryFrom(currency, repaymentPeriods, loanRepayments);
this.currency = currency;
this.repaymentPeriods = repaymentPeriods;
}
private LoanAccountSummaryData derivedSummaryFrom(
final CurrencyData currency,
final Collection<LoanRepaymentPeriodData> repaymentSchedule,
final Collection<LoanRepaymentTransactionData> loanRepayments) {
BigDecimal originalPrincipal = BigDecimal.ZERO;
BigDecimal principalPaid = BigDecimal.ZERO;
BigDecimal principalOutstanding = BigDecimal.ZERO;
BigDecimal originalInterest = BigDecimal.ZERO;
BigDecimal interestPaid = BigDecimal.ZERO;
BigDecimal interestWaived = BigDecimal.ZERO;
BigDecimal interestOutstanding = BigDecimal.ZERO;
BigDecimal originalTotal = BigDecimal.ZERO;
BigDecimal totalPaid = BigDecimal.ZERO;
BigDecimal totalWaived = BigDecimal.ZERO;
BigDecimal totalOutstanding = BigDecimal.ZERO;
BigDecimal totalInArrears = BigDecimal.ZERO;
for (LoanRepaymentPeriodData installment : repaymentSchedule) {
originalPrincipal = originalPrincipal.add(installment.getPrincipal());
principalPaid = principalPaid.add(installment.getPrincipalPaid());
principalOutstanding = principalOutstanding.add(installment.getPrincipalOutstanding());
originalInterest = originalInterest.add(installment.getInterest());
interestPaid = interestPaid.add(installment.getInterestPaid());
interestWaived = interestWaived.add(installment.getInterestWaived());
interestOutstanding = interestOutstanding.add(installment.getInterestOutstanding());
originalTotal = originalTotal.add(installment.getTotal());
totalPaid = totalPaid.add(installment.getTotalPaid());
totalWaived = totalWaived.add(installment.getTotalWaived());
totalOutstanding = totalOutstanding.add(installment.getTotalOutstanding());
if (installment.getDate().isBefore(new LocalDate())) {
totalInArrears = totalInArrears.add(installment.getTotalOutstanding());
}
}
// sum up all repayment transactions
Long waiverType = (long) 4;
MoneyData totalRepaymentAmount = MoneyData.of(currency,BigDecimal.ZERO);
if (loanRepayments != null) {
for (LoanRepaymentTransactionData loanRepayment : loanRepayments) {
Long transactionType = loanRepayment.getTransactionType().getId();
if (transactionType.equals(waiverType)) {
// skip
} else {
totalRepaymentAmount = totalRepaymentAmount.plus(loanRepayment.getTotal());
}
}
}
// detect if loan is in overpaid state
if (totalRepaymentAmount.isGreaterThan(MoneyData.of(currency, totalPaid))) {
BigDecimal difference = totalRepaymentAmount.getAmount().subtract(totalPaid);
totalOutstanding = totalOutstanding.subtract(difference);
}
return new LoanAccountSummaryData(currency, originalPrincipal,
principalPaid, principalOutstanding, originalInterest,
interestPaid, interestWaived, interestOutstanding,
originalTotal, totalPaid, totalWaived, totalOutstanding,
totalInArrears);
}
public BigDecimal totalOutstanding() {
return this.summary.totalOutstanding();
}
}
@@ -147,7 +147,7 @@ public class GoogleGsonApiJsonSerializerService implements ApiJsonSerializerServ
"expectedFirstRepaymentOnDate", "interestChargedFromDate", "expectedFirstRepaymentOnDate", "interestChargedFromDate",
"closedOnDate", "expectedMaturityDate", "closedOnDate", "expectedMaturityDate",
"status", "status",
"lifeCycleStatusDate", "summary", "repaymentSchedule", "lifeCycleStatusDate", "repaymentSchedule",
"loanRepayments", "permissions", "convenienceData", "charges", "loanRepayments", "permissions", "convenienceData", "charges",
"productOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", "productOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions",
"repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "repaymentStrategyOptions", "chargeOptions", "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "repaymentStrategyOptions", "chargeOptions",
@@ -3,25 +3,20 @@ package org.mifosng.platform.loan.service;
import java.util.Collection; import java.util.Collection;
import org.mifosng.platform.api.data.CurrencyData; import org.mifosng.platform.api.data.CurrencyData;
import org.mifosng.platform.api.data.LoanAccountSummaryData;
import org.mifosng.platform.api.data.LoanBasicDetailsData; import org.mifosng.platform.api.data.LoanBasicDetailsData;
import org.mifosng.platform.api.data.LoanPermissionData; import org.mifosng.platform.api.data.LoanPermissionData;
import org.mifosng.platform.api.data.LoanRepaymentPeriodData;
import org.mifosng.platform.api.data.LoanRepaymentTransactionData; import org.mifosng.platform.api.data.LoanRepaymentTransactionData;
import org.mifosng.platform.api.data.LoanScheduleData;
import org.mifosng.platform.api.data.LoanTransactionData; import org.mifosng.platform.api.data.LoanTransactionData;
public interface LoanReadPlatformService { public interface LoanReadPlatformService {
LoanBasicDetailsData retrieveLoanAccountDetails(Long loanId); LoanBasicDetailsData retrieveLoanAccountDetails(Long loanId);
Collection<LoanRepaymentPeriodData> retrieveRepaymentSchedule(Long loanId); LoanScheduleData retrieveRepaymentSchedule(Long loanId, CurrencyData currencyData, Collection<LoanRepaymentTransactionData> loanRepayments);
Collection<LoanRepaymentTransactionData> retrieveLoanPayments(Long loanId); Collection<LoanRepaymentTransactionData> retrieveLoanPayments(Long loanId);
LoanAccountSummaryData retrieveSummary(CurrencyData currency,
Collection<LoanRepaymentPeriodData> repaymentSchedule,
Collection<LoanRepaymentTransactionData> loanRepayments);
LoanPermissionData retrieveLoanPermissions( LoanPermissionData retrieveLoanPermissions(
LoanBasicDetailsData loanBasicDetails, boolean isWaiverAllowed, LoanBasicDetailsData loanBasicDetails, boolean isWaiverAllowed,
int repaymentAndWaiveCount); int repaymentAndWaiveCount);
@@ -10,12 +10,12 @@ import org.mifosng.platform.api.data.ChargeData;
import org.mifosng.platform.api.data.ClientData; import org.mifosng.platform.api.data.ClientData;
import org.mifosng.platform.api.data.CurrencyData; import org.mifosng.platform.api.data.CurrencyData;
import org.mifosng.platform.api.data.EnumOptionData; import org.mifosng.platform.api.data.EnumOptionData;
import org.mifosng.platform.api.data.LoanAccountSummaryData;
import org.mifosng.platform.api.data.LoanBasicDetailsData; import org.mifosng.platform.api.data.LoanBasicDetailsData;
import org.mifosng.platform.api.data.LoanPermissionData; import org.mifosng.platform.api.data.LoanPermissionData;
import org.mifosng.platform.api.data.LoanProductData; import org.mifosng.platform.api.data.LoanProductData;
import org.mifosng.platform.api.data.LoanRepaymentPeriodData; import org.mifosng.platform.api.data.LoanRepaymentPeriodData;
import org.mifosng.platform.api.data.LoanRepaymentTransactionData; import org.mifosng.platform.api.data.LoanRepaymentTransactionData;
import org.mifosng.platform.api.data.LoanScheduleData;
import org.mifosng.platform.api.data.LoanTransactionData; import org.mifosng.platform.api.data.LoanTransactionData;
import org.mifosng.platform.api.data.MoneyData; import org.mifosng.platform.api.data.MoneyData;
import org.mifosng.platform.client.service.ClientReadPlatformService; import org.mifosng.platform.client.service.ClientReadPlatformService;
@@ -89,8 +89,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
} }
@Override @Override
public Collection<LoanRepaymentPeriodData> retrieveRepaymentSchedule( public LoanScheduleData retrieveRepaymentSchedule(final Long loanId, final CurrencyData currency, final Collection<LoanRepaymentTransactionData> loanRepayments) {
Long loanId) {
try { try {
context.authenticatedUser(); context.authenticatedUser();
@@ -98,88 +97,14 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
LoanScheduleMapper rm = new LoanScheduleMapper(); LoanScheduleMapper rm = new LoanScheduleMapper();
String sql = "select " + rm.loanScheduleSchema() String sql = "select " + rm.loanScheduleSchema()
+ " where l.id = ? order by ls.loan_id, ls.installment"; + " where l.id = ? order by ls.loan_id, ls.installment";
return this.jdbcTemplate.query(sql, rm, new Object[] { loanId }); Collection<LoanRepaymentPeriodData> repaymentSchedulePeriods = this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
return new LoanScheduleData(currency, repaymentSchedulePeriods, loanRepayments);
} catch (EmptyResultDataAccessException e) { } catch (EmptyResultDataAccessException e) {
throw new LoanNotFoundException(loanId); throw new LoanNotFoundException(loanId);
} }
} }
@Override
public LoanAccountSummaryData retrieveSummary(
final CurrencyData currencyData,
final Collection<LoanRepaymentPeriodData> repaymentSchedule,
final Collection<LoanRepaymentTransactionData> loanRepayments) {
BigDecimal originalPrincipal = BigDecimal.ZERO;
BigDecimal principalPaid = BigDecimal.ZERO;
BigDecimal principalOutstanding = BigDecimal.ZERO;
BigDecimal originalInterest = BigDecimal.ZERO;
BigDecimal interestPaid = BigDecimal.ZERO;
BigDecimal interestWaived = BigDecimal.ZERO;
BigDecimal interestOutstanding = BigDecimal.ZERO;
BigDecimal originalTotal = BigDecimal.ZERO;
BigDecimal totalPaid = BigDecimal.ZERO;
BigDecimal totalWaived = BigDecimal.ZERO;
BigDecimal totalOutstanding = BigDecimal.ZERO;
BigDecimal totalInArrears = BigDecimal.ZERO;
for (LoanRepaymentPeriodData installment : repaymentSchedule) {
originalPrincipal = originalPrincipal.add(installment.getPrincipal().getAmount());
principalPaid = principalPaid.add(installment.getPrincipalPaid().getAmount());
principalOutstanding = principalOutstanding.add(installment.getPrincipalOutstanding().getAmount());
originalInterest = originalInterest.add(installment.getInterest().getAmount());
interestPaid = interestPaid.add(installment.getInterestPaid().getAmount());
interestWaived = interestWaived.add(installment.getInterestWaived().getAmount());
interestOutstanding = interestOutstanding.add(installment.getInterestOutstanding().getAmount());
originalTotal = originalTotal.add(installment.getTotal().getAmount());
totalPaid = totalPaid.add(installment.getTotalPaid().getAmount());
totalWaived = totalWaived.add(installment.getTotalWaived().getAmount());
totalOutstanding = totalOutstanding.add(installment.getTotalOutstanding().getAmount());
if (installment.getDate().isBefore(new LocalDate())) {
totalInArrears = totalInArrears.add(installment.getTotalOutstanding().getAmount());
}
}
// sum up all repayment transactions
Long waiverType = (long) 4;
MoneyData totalRepaymentAmount = MoneyData.of(currencyData, BigDecimal.ZERO);
if (loanRepayments != null) {
for (LoanRepaymentTransactionData loanRepayment : loanRepayments) {
Long transactionType = loanRepayment.getTransactionType().getId();
if (transactionType.equals(waiverType)) {
// skip
} else {
totalRepaymentAmount = totalRepaymentAmount.plus(loanRepayment.getTotal());
}
}
}
// detect if loan is in overpaid state
if (totalRepaymentAmount.isGreaterThan(MoneyData.of(currencyData, totalPaid))) {
BigDecimal difference = totalRepaymentAmount.getAmount().subtract(totalPaid);
totalOutstanding = totalOutstanding.subtract(difference);
}
return new LoanAccountSummaryData(
MoneyData.of(currencyData,originalPrincipal),
MoneyData.of(currencyData, principalPaid),
MoneyData.of(currencyData, principalOutstanding),
MoneyData.of(currencyData, originalInterest),
MoneyData.of(currencyData, interestPaid),
MoneyData.of(currencyData, interestWaived),
MoneyData.of(currencyData, interestOutstanding),
MoneyData.of(currencyData, originalTotal),
MoneyData.of(currencyData, totalPaid),
MoneyData.of(currencyData, totalWaived),
MoneyData.of(currencyData, totalOutstanding),
MoneyData.of(currencyData, totalInArrears));
}
@Override @Override
public Collection<LoanRepaymentTransactionData> retrieveLoanPayments(Long loanId) { public Collection<LoanRepaymentTransactionData> retrieveLoanPayments(Long loanId) {
try { try {
@@ -516,13 +441,12 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
public LoanRepaymentPeriodData mapRow(final ResultSet rs, public LoanRepaymentPeriodData mapRow(final ResultSet rs,
final int rowNum) throws SQLException { final int rowNum) throws SQLException {
// FIXME - kw - currency not need per installment period any longer, just at loan schedule level.
String currencyCode = rs.getString("currencyCode"); String currencyCode = rs.getString("currencyCode");
String currencyName = rs.getString("currencyName"); String currencyName = rs.getString("currencyName");
String currencyNameCode = rs.getString("currencyNameCode"); String currencyNameCode = rs.getString("currencyNameCode");
String currencyDisplaySymbol = rs String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
.getString("currencyDisplaySymbol"); Integer currencyDigits = JdbcSupport.getInteger(rs,"currencyDigits");
Integer currencyDigits = JdbcSupport.getInteger(rs,
"currencyDigits");
CurrencyData currencyData = new CurrencyData(currencyCode, CurrencyData currencyData = new CurrencyData(currencyCode,
currencyName, currencyDigits, currencyDisplaySymbol, currencyName, currencyDigits, currencyDisplaySymbol,
currencyNameCode); currencyNameCode);
@@ -531,28 +455,22 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
Integer period = JdbcSupport.getInteger(rs, "period"); Integer period = JdbcSupport.getInteger(rs, "period");
LocalDate date = JdbcSupport.getLocalDate(rs, "date"); LocalDate date = JdbcSupport.getLocalDate(rs, "date");
BigDecimal principalBD = rs.getBigDecimal("principal"); BigDecimal principal = rs.getBigDecimal("principal");
MoneyData principal = MoneyData.of(currencyData, principalBD); BigDecimal principalPaid = rs.getBigDecimal("principalPaid");
BigDecimal principalPaidBD = rs.getBigDecimal("principalPaid"); BigDecimal principalOutstanding = principal.subtract(principalPaid);
MoneyData principalPaid = MoneyData.of(currencyData, principalPaidBD);
MoneyData principalOutstanding = MoneyData.of(currencyData,principalBD.subtract(principalPaidBD));
BigDecimal interestBD = rs.getBigDecimal("interest"); BigDecimal interest = rs.getBigDecimal("interest");
MoneyData interest = MoneyData.of(currencyData, interestBD); BigDecimal interestPaid = rs.getBigDecimal("interestPaid");
BigDecimal interestPaidBD = rs.getBigDecimal("interestPaid"); BigDecimal interestWaived = rs.getBigDecimal("interestWaived");
MoneyData interestPaid = MoneyData.of(currencyData, interestPaidBD); if (interestWaived == null) {
interestWaived = BigDecimal.ZERO;
BigDecimal interestWaivedBD = rs.getBigDecimal("interestWaived");
if (interestWaivedBD == null) {
interestWaivedBD = BigDecimal.ZERO;
} }
MoneyData interestWaived = MoneyData.of(currencyData, interestWaivedBD); BigDecimal interestOutstanding = interest.subtract(interestPaid).subtract(interestWaived);
MoneyData interestOutstanding = MoneyData.of(currencyData, interestBD.subtract(interestPaidBD).subtract(interestWaivedBD));
MoneyData total = MoneyData.of(currencyData,principalBD.add(interestBD)); BigDecimal total = principal.add(interest);
MoneyData totalPaid = principalPaid.plus(interestPaid); BigDecimal totalPaid = principalPaid.add(interestPaid);
MoneyData totalWaived = interestWaived; BigDecimal totalWaived = interestWaived;
MoneyData totalOutstanding = principalOutstanding.plus(interestOutstanding); BigDecimal totalOutstanding = principalOutstanding.add(interestOutstanding);
return new LoanRepaymentPeriodData(loanId, period, date, return new LoanRepaymentPeriodData(loanId, period, date,
principal, principalPaid, principalOutstanding, interest, principal, principalPaid, principalOutstanding, interest,