remove legacy code and fetaures from earlier prototype version that are no longer used and will be implemented differently in future.

This commit is contained in:
Keith Woodlock
2012-10-10 17:00:05 +01:00
parent c4578672fa
commit b79f0495f3
18 changed files with 83 additions and 768 deletions
@@ -0,0 +1,6 @@
alter table m_product_loan drop column flexible_repayment_schedule;
alter table m_product_loan drop column interest_rebate;
alter table m_loan drop column flexible_repayment_schedule;
alter table m_loan drop column interest_rebate;
alter table m_loan drop column interest_rebate_amount;
@@ -1,62 +0,0 @@
package org.mifosng.platform.api.data;
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")
@Deprecated
public class LoanAccountSummaryData {
private final CurrencyData currency;
private final BigDecimal originalPrincipal;
private final BigDecimal originalInterest;
private final BigDecimal originalTotal;
private final BigDecimal principalPaid;
private final BigDecimal principalOutstanding;
private final BigDecimal interestPaid;
private final BigDecimal interestWaived;
private final BigDecimal interestOutstanding;
private final BigDecimal totalPaid;
private final BigDecimal totalWaived;
private final BigDecimal totalOutstanding;
private final BigDecimal totalInArrears;
public LoanAccountSummaryData(
final CurrencyData currency,
final BigDecimal originalPrincipal,
final BigDecimal principalPaid,
final BigDecimal principalOutstanding,
final BigDecimal originalInterest,
final BigDecimal interestPaid,
final BigDecimal interestWaived,
final BigDecimal interestOutstanding,
final BigDecimal originalTotal,
final BigDecimal totalPaid,
final BigDecimal totalWaived,
final BigDecimal totalOutstanding,
final BigDecimal totalInArrears) {
this.currency = currency;
this.originalPrincipal = originalPrincipal;
this.principalPaid = principalPaid;
this.principalOutstanding = principalOutstanding;
this.originalInterest = originalInterest;
this.interestPaid = interestPaid;
this.interestWaived = interestWaived;
this.interestOutstanding = interestOutstanding;
this.originalTotal = originalTotal;
this.totalPaid = totalPaid;
this.totalWaived = totalWaived;
this.totalOutstanding = totalOutstanding;
this.totalInArrears = totalInArrears;
}
public BigDecimal totalOutstanding() {
return this.totalOutstanding;
}
}
@@ -1,131 +0,0 @@
package org.mifosng.platform.loan.domain;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.mifosng.platform.currency.domain.MonetaryCurrency;
import org.mifosng.platform.currency.domain.Money;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Deprecated
public class DailyEquivalentDecliningBalanceInterestRebateCalculator implements
InterestRebateCalculator {
private final static Logger logger = LoggerFactory
.getLogger(DailyEquivalentDecliningBalanceInterestRebateCalculator.class);
@Override
public Money calculate(
final LocalDate actualDisbursementDate,
final LocalDate paidInFullDate,
final Money loanPrincipal,
final BigDecimal interestRatePerAnnum,
final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
final List<LoanTransaction> loanRepayments) {
MonetaryCurrency currency = loanPrincipal.getCurrency();
Money totalOriginalInterest = getTotalInterestOnLoan(currency, repaymentScheduleInstallments);
BigDecimal dailyEquivalentPeriodicInterestRate = interestRatePerAnnum
.divide(BigDecimal.valueOf(36500), 9, RoundingMode.HALF_EVEN);
Money totalRecalculatedPrincipalPaid = Money.zero(loanPrincipal.getCurrency());
Money totalRecalculatedInterestPaid = Money.zero(loanPrincipal.getCurrency());
LocalDate lastBalanceDate = actualDisbursementDate;
Money outstandingBalance = loanPrincipal;
for (LoanTransaction loanRepayment : loanRepayments) {
int daysAtBalance = Days.daysBetween(lastBalanceDate,
loanRepayment.getTransactionDate()).getDays();
BigDecimal periodInterestRateForPaymentPeriod = dailyEquivalentPeriodicInterestRate.multiply(BigDecimal.valueOf(daysAtBalance));
BigDecimal interestDueOnPaymentDateAmount = outstandingBalance.getAmount().multiply(periodInterestRateForPaymentPeriod);
Money interestDueOnPaymentDate = Money.of(loanPrincipal.getCurrency(),interestDueOnPaymentDateAmount);
Money principalDueOnPaymentDate = loanRepayment.getAmount(currency).minus(interestDueOnPaymentDate);
totalRecalculatedPrincipalPaid = totalRecalculatedPrincipalPaid.plus(principalDueOnPaymentDate);
totalRecalculatedInterestPaid = totalRecalculatedInterestPaid.plus(interestDueOnPaymentDate);
logger.warn("Installment: " + lastBalanceDate + " - "
+ loanRepayment.getTransactionDate() + " principal: "
+ principalDueOnPaymentDate + "interest: "
+ interestDueOnPaymentDate + " total: "
+ loanRepayment.getAmount());
lastBalanceDate = loanRepayment.getTransactionDate();
outstandingBalance = outstandingBalance
.minus(principalDueOnPaymentDate);
}
// finally
// add up total paid to date - work out interest due on that
int daysAtBalance = Days.daysBetween(lastBalanceDate, paidInFullDate)
.getDays();
BigDecimal periodInterestRateForPaymentPeriod = dailyEquivalentPeriodicInterestRate
.multiply(BigDecimal.valueOf(daysAtBalance));
BigDecimal interestDueOnPaymentDateAmount = outstandingBalance
.getAmount().multiply(periodInterestRateForPaymentPeriod);
Money interestDueOnPaymentDate = Money.of(
loanPrincipal.getCurrency(),
interestDueOnPaymentDateAmount);
Money principalDueOnPaymentDate = outstandingBalance;
Money netOutstandingOnPaidInFullDate = principalDueOnPaymentDate
.plus(interestDueOnPaymentDate);
totalRecalculatedPrincipalPaid = totalRecalculatedPrincipalPaid.plus(principalDueOnPaymentDate);
totalRecalculatedInterestPaid = totalRecalculatedInterestPaid.plus(interestDueOnPaymentDate);
logger.warn("Installment: " + lastBalanceDate + " - " + paidInFullDate
+ " principal: " + principalDueOnPaymentDate + "interest: "
+ interestDueOnPaymentDate + " total: "
+ netOutstandingOnPaidInFullDate);
lastBalanceDate = paidInFullDate;
outstandingBalance = outstandingBalance
.minus(principalDueOnPaymentDate);
Money rebate = Money.zero(loanPrincipal.getCurrency());
// Interest can be greater for following reasons:
// 1. calculated interest may be slightly ahead based on daily
// equivalent
// method of calculating interest compared to original method.
// 2. payments were under expected amount or after expected date
// resulting in larger outstanding balance being used to calculate
// interest
// at each repayment point in time.
if (totalRecalculatedInterestPaid.isLessThan(totalOriginalInterest)
&& totalRecalculatedInterestPaid.isGreaterThanZero()) {
rebate = totalOriginalInterest.minus(totalRecalculatedInterestPaid);
}
return rebate;
}
private Money getTotalInterestOnLoan(
final MonetaryCurrency currency,
final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments) {
Money cumulativeInterest = Money.zero(currency);
for (LoanRepaymentScheduleInstallment scheduledRepayment : repaymentScheduleInstallments) {
cumulativeInterest = cumulativeInterest.plus(scheduledRepayment
.getInterest(currency));
}
return cumulativeInterest;
}
}
@@ -1,72 +0,0 @@
package org.mifosng.platform.loan.domain;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.mifosng.platform.currency.domain.MonetaryCurrency;
import org.mifosng.platform.currency.domain.Money;
@SuppressWarnings("unused")
@Deprecated
public class DailyEquivalentFlatInterestRebateCalculator implements
InterestRebateCalculator {
@Override
public Money calculate(
final LocalDate actualDisbursementDate,
final LocalDate paidInFullDate,
final Money loanPrincipal,
final BigDecimal interestRatePerAnnum,
final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
final List<LoanTransaction> loanRepayments) {
MonetaryCurrency currency = loanPrincipal.getCurrency();
LocalDate maturityDate = repaymentScheduleInstallments.get(
repaymentScheduleInstallments.size() - 1).getDueDate();
int daysEquivalentOfLoanTerm = Days.daysBetween(actualDisbursementDate,
maturityDate).getDays();
Money totalOriginalInterest = getTotalInterestOnLoan(
currency,
repaymentScheduleInstallments);
int actualLoanTermInDays = Days.daysBetween(actualDisbursementDate,
paidInFullDate).getDays();
BigDecimal divisor = loanPrincipal.getAmount().multiply(
BigDecimal.valueOf(daysEquivalentOfLoanTerm));
BigDecimal periodicInterestRate = totalOriginalInterest.getAmount().divide(
divisor, 9, RoundingMode.HALF_EVEN);
Money totalRecalculatedInterest = loanPrincipal.multipliedBy(
periodicInterestRate).multipliedBy(actualLoanTermInDays);
Money rebate = Money.zero(loanPrincipal.getCurrency());
if (totalRecalculatedInterest.isLessThan(totalOriginalInterest)
&& totalRecalculatedInterest.isGreaterThanZero()) {
rebate = totalOriginalInterest.minus(totalRecalculatedInterest);
}
return rebate;
}
private Money getTotalInterestOnLoan(
final MonetaryCurrency currency,
final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments) {
Money cumulativeInterest = Money.zero(currency);
for (LoanRepaymentScheduleInstallment scheduledRepayment : repaymentScheduleInstallments) {
cumulativeInterest = cumulativeInterest.plus(scheduledRepayment
.getInterest(currency));
}
return cumulativeInterest;
}
}
@@ -1,34 +0,0 @@
package org.mifosng.platform.loan.domain;
public class DailyEquivalentInterestRebateCalculatorFactory implements
InterestRebateCalculatorFactory {
@Override
public InterestRebateCalculator createCalcualtor(
final InterestMethod loanRepaymentScheduleMethod, final AmortizationMethod amortizationMethod) {
InterestRebateCalculator interestRebateCalculator = null;
switch (loanRepaymentScheduleMethod) {
case DECLINING_BALANCE:
switch (amortizationMethod) {
case EQUAL_INSTALLMENTS:
interestRebateCalculator = new DailyEquivalentDecliningBalanceInterestRebateCalculator();
break;
default:
interestRebateCalculator = new DailyEquivalentDecliningBalanceInterestRebateCalculator();
break;
}
break;
case FLAT:
interestRebateCalculator = new DailyEquivalentFlatInterestRebateCalculator();
break;
default:
interestRebateCalculator = new DailyEquivalentFlatInterestRebateCalculator();
break;
}
return interestRebateCalculator;
}
}
@@ -1,20 +0,0 @@
package org.mifosng.platform.loan.domain;
import java.math.BigDecimal;
import java.util.List;
import org.joda.time.LocalDate;
import org.mifosng.platform.currency.domain.Money;
@Deprecated
public interface InterestRebateCalculator {
Money calculate(
LocalDate actualDisbursementDate,
LocalDate paidInFullDate,
Money loanPrincipal,
BigDecimal interestRatePerAnnum,
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments,
List<LoanTransaction> loanRepayments);
}
@@ -1,9 +0,0 @@
package org.mifosng.platform.loan.domain;
public interface InterestRebateCalculatorFactory {
InterestRebateCalculator createCalcualtor(
InterestMethod loanRepaymentScheduleMethod,
AmortizationMethod amortizationMethod);
}
@@ -156,15 +156,9 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true)
private final List<LoanTransaction> loanTransactions = new ArrayList<LoanTransaction>();
@Column(name = "interest_rebate_amount", scale = 6, precision = 19)
private BigDecimal interestRebateOwed;
@Column(name = "total_charges_due_at_disbursement_derived", scale = 6, precision = 19)
private BigDecimal totalChargesDueAtDisbursement;
@Transient
private final InterestRebateCalculatorFactory interestRebateCalculatorFactory = new DailyEquivalentInterestRebateCalculatorFactory();
@Transient
private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessor = new LoanRepaymentScheduleTransactionProcessorFactory();
@@ -211,7 +205,6 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
} else {
this.charges = null;
}
this.interestRebateOwed = BigDecimal.ZERO;
}
private Loan(
@@ -237,7 +230,6 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
} else {
this.charges = null;
}
this.interestRebateOwed = BigDecimal.ZERO;
}
private BigDecimal deriveSumTotalOfChargesDueAtDisbursement() {
@@ -445,8 +437,9 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
}
}
public void withdraw(final LocalDate withdrawnOn,
LoanLifecycleStateMachine loanLifecycleStateMachine) {
public void withdraw(
final LocalDate withdrawnOn,
final LoanLifecycleStateMachine loanLifecycleStateMachine) {
LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_WITHDRAWN, LoanStatus.fromInt(this.loanStatus));
this.loanStatus = statusEnum.getValue();
@@ -697,16 +690,6 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
this.closedOnDate = loanTransaction.getTransactionDate().toDate();
this.maturedOnDate = loanTransaction.getTransactionDate().toDate();
if (isInterestRebateAllowed()) {
Money rebateDue = calculateRebateWhenPaidInFullOn(loanTransaction.getTransactionDate());
if (rebateDue.isGreaterThanZero()) {
statusEnum = loanLifecycleStateMachine.transition(LoanEvent.INTERST_REBATE_OWED, LoanStatus.fromInt(this.loanStatus));
this.loanStatus = statusEnum.getValue();
this.interestRebateOwed = rebateDue.getAmount();
}
}
}
private void handleLoanOverpayment(@SuppressWarnings("unused") final LoanTransaction loanTransaction, final LoanLifecycleStateMachine loanLifecycleStateMachine) {
@@ -991,6 +974,16 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return loanTransaction;
}
private Money getTotalOutstanding() {
Money totalOutstanding = Money.zero(loanCurrency());
// 1. check totalOutstanding value on loan
// 2. if null calculate from loan schedule
final LoanScheduleWrapper wrapper = new LoanScheduleWrapper();
totalOutstanding = wrapper.calculateTotalOutstanding(loanCurrency(), this.repaymentScheduleInstallments);
return totalOutstanding;
}
private void updateLoanForClosure(final LocalDate closureDate, final LoanLifecycleStateMachine loanLifecycleStateMachine) {
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.REPAID_IN_FULL, LoanStatus.fromInt(this.loanStatus));
this.loanStatus = statusEnum.getValue();
@@ -1258,66 +1251,18 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
.isEqual(actualDisbursedOnDate);
}
public boolean isFlexibleRepaymentSchedule() {
return this.loanProduct.isFlexibleRepaymentSchedule();
}
public boolean isInterestRebateAllowed() {
return this.loanProduct.isInterestRebateAllowed();
}
public boolean isRepaymentScheduleRegenerationRequiredForDisbursement(
final LocalDate actualDisbursementDate) {
boolean regenerationRequired = false;
if (isFlexibleRepaymentSchedule()) {
regenerationRequired = false;
} else {
if (isActualDisbursedOnDateEarlierOrLaterThanExpected(actualDisbursementDate)) {
regenerationRequired = true;
}
if (isActualDisbursedOnDateEarlierOrLaterThanExpected(actualDisbursementDate)) {
regenerationRequired = true;
}
return regenerationRequired;
}
@Deprecated
public LoanPayoffSummary getPayoffSummaryOn(
final LocalDate projectedPayoffDate) {
LocalDate acutalDisbursementDate = new LocalDate(this.disbursedOnDate);
Money totalPaidToDate = this.getTotalPaidInRepayments();
Money totalOutstandingBasedOnExpectedMaturityDate = this
.getTotalOutstanding();
Money totalOutstandingBasedOnPayoffDate = totalOutstandingBasedOnExpectedMaturityDate;
Money rebateGivenOnProjectedPayoffDate = Money
.zero(this.loanRepaymentScheduleDetail.getPrincipal()
.getCurrency());
if (isInterestRebateAllowed()) {
rebateGivenOnProjectedPayoffDate = calculateRebateWhenPaidInFullOn(projectedPayoffDate);
totalOutstandingBasedOnPayoffDate = totalOutstandingBasedOnExpectedMaturityDate
.minus(rebateGivenOnProjectedPayoffDate);
}
return new LoanPayoffSummary(this.getId(), acutalDisbursementDate,
this.getMaturityDate(), projectedPayoffDate, totalPaidToDate,
totalOutstandingBasedOnExpectedMaturityDate,
totalOutstandingBasedOnPayoffDate,
rebateGivenOnProjectedPayoffDate);
}
/*
* FIXME - KW - change what outstanding balance on loan can be accessed. This total outstanding method is wrong and
*/
@Deprecated
public Money getTotalOutstanding() {
return getTotalPrincipalOnLoan().plus(getTotalInterestOnLoan()).minus(getTotalPaidInRepayments());
}
private Money getTotalPaidInRepayments() {
Money cumulativePaid = Money.zero(this.loanRepaymentScheduleDetail.getPrincipal().getCurrency());
@@ -1330,40 +1275,15 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return cumulativePaid;
}
@Deprecated
public Money calculateRebateWhenPaidInFullOn(final LocalDate paidInFullDate) {
Money loanPrincipal = this.loanRepaymentScheduleDetail.getPrincipal();
Money rebate = Money.zero(loanPrincipal.getCurrency());
if (this.isDisbursed()
&& !paidInFullDate.isBefore(this.getDisbursementDate())) {
InterestRebateCalculator interestRebateCalculator = this.interestRebateCalculatorFactory
.createCalcualtor(this.loanRepaymentScheduleDetail
.getInterestMethod(),
this.loanRepaymentScheduleDetail
.getAmortizationMethod());
rebate = interestRebateCalculator.calculate(this
.getDisbursementDate(), paidInFullDate, loanPrincipal,
this.loanRepaymentScheduleDetail
.getAnnualNominalInterestRate(),
this.repaymentScheduleInstallments, this.loanTransactions);
}
return rebate;
}
private Money getTotalInterestOnLoan() {
Money cumulativeInterest = Money.zero(loanCurrency());
for (LoanRepaymentScheduleInstallment scheduledRepayment : this.repaymentScheduleInstallments) {
cumulativeInterest = cumulativeInterest.plus(scheduledRepayment.getInterest(loanCurrency()));
}
return cumulativeInterest;
}
// private Money getTotalInterestOnLoan() {
// Money cumulativeInterest = Money.zero(loanCurrency());
//
// for (LoanRepaymentScheduleInstallment scheduledRepayment : this.repaymentScheduleInstallments) {
// cumulativeInterest = cumulativeInterest.plus(scheduledRepayment.getInterest(loanCurrency()));
// }
//
// return cumulativeInterest;
// }
private Money getTotalInterestOutstandingOnLoan() {
Money cumulativeInterest = Money.zero(loanCurrency());
@@ -1390,24 +1310,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return cumulativeInterestOverdue;
}
private Money getTotalPrincipalOnLoan() {
Money cumulativePrincipal = Money.zero(this.loanRepaymentScheduleDetail
.getPrincipal().getCurrency());
for (LoanRepaymentScheduleInstallment scheduledRepayment : this.repaymentScheduleInstallments) {
cumulativePrincipal = cumulativePrincipal.plus(scheduledRepayment
.getPrincipal(loanCurrency()));
}
return cumulativePrincipal;
}
public Money getInterestRebateOwed() {
return Money.of(this.loanRepaymentScheduleDetail.getCurrency(),
this.interestRebateOwed);
}
public Money getInArrearsTolerance() {
private Money getInArrearsTolerance() {
return this.loanRepaymentScheduleDetail.getInArrearsTolerance();
}
@@ -1416,10 +1319,6 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|| identifier.equalsIgnoreCase(this.getId().toString());
}
public MonetaryCurrency getCurrency() {
return this.loanRepaymentScheduleDetail.getCurrency();
}
public LocalDate getInterestChargedFromDate() {
LocalDate interestChargedFrom = null;
if (this.interestChargedFromDate != null) {
@@ -1446,11 +1345,6 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return statusSinceDate;
}
public String getCurrencyCode() {
return this.loanRepaymentScheduleDetail.getPrincipal()
.getCurrencyCode();
}
public Money getPrincpal() {
return this.loanRepaymentScheduleDetail.getPrincipal();
}
@@ -1458,4 +1352,16 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
public Money getTotalChargesDueAtDisbursement() {
return Money.of(getCurrency(), this.totalChargesDueAtDisbursement);
}
public boolean hasCurrencyCodeOf(final String matchingCurrencyCode) {
return getCurrencyCode().equalsIgnoreCase(matchingCurrencyCode);
}
private String getCurrencyCode() {
return this.loanRepaymentScheduleDetail.getPrincipal().getCurrencyCode();
}
private MonetaryCurrency getCurrency() {
return this.loanRepaymentScheduleDetail.getCurrency();
}
}
@@ -1,77 +0,0 @@
package org.mifosng.platform.loan.domain;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.mifosng.platform.currency.domain.Money;
@Deprecated
public class LoanPayoffSummary {
private final Long reference;
private final LocalDate acutalDisbursementDate;
private final LocalDate expectedMaturityDate;
private final LocalDate projectedMaturityDate;
private final Money totalPaidToDate;
private final Money totalOutstandingBasedOnExpectedMaturityDate;
private final Money totalOutstandingBasedOnPayoffDate;
private final Money rebateOwed;
public LoanPayoffSummary(final Long reference,
final LocalDate acutalDisbursementDate,
final LocalDate expectedMaturityDate,
final LocalDate projectedMaturityDate, final Money totalPaidToDate,
final Money totalOutstandingBasedOnExpectedMaturityDate,
final Money totalOutstandingBasedOnPayoffDate,
final Money rebateOwed) {
this.reference = reference;
this.acutalDisbursementDate = acutalDisbursementDate;
this.expectedMaturityDate = expectedMaturityDate;
this.projectedMaturityDate = projectedMaturityDate;
this.totalPaidToDate = totalPaidToDate;
this.totalOutstandingBasedOnExpectedMaturityDate = totalOutstandingBasedOnExpectedMaturityDate;
this.totalOutstandingBasedOnPayoffDate = totalOutstandingBasedOnPayoffDate;
this.rebateOwed = rebateOwed;
}
public Long getReference() {
return this.reference;
}
public LocalDate getAcutalDisbursementDate() {
return this.acutalDisbursementDate;
}
public LocalDate getExpectedMaturityDate() {
return this.expectedMaturityDate;
}
public LocalDate getProjectedMaturityDate() {
return this.projectedMaturityDate;
}
public Money getTotalPaidToDate() {
return this.totalPaidToDate;
}
public Money getRebateOwed() {
return this.rebateOwed;
}
public Integer getExpectedLoanTermInDays() {
return Days.daysBetween(this.acutalDisbursementDate,
this.expectedMaturityDate).getDays();
}
public Integer getProjectedLoanTermInDays() {
return Days.daysBetween(this.acutalDisbursementDate,
this.projectedMaturityDate).getDays();
}
public Money getTotalOutstandingBasedOnExpectedMaturityDate() {
return this.totalOutstandingBasedOnExpectedMaturityDate;
}
public Money getTotalOutstandingBasedOnPayoffDate() {
return this.totalOutstandingBasedOnPayoffDate;
}
}
@@ -108,14 +108,6 @@ public class LoanProduct extends AbstractAuditableCustom<AppUser, Long> {
return this.loanProductRelatedDetail.getRepayEvery();
}
public boolean isFlexibleRepaymentSchedule() {
return this.loanProductRelatedDetail.isFlexibleRepaymentSchedule();
}
public boolean isInterestRebateAllowed() {
return this.loanProductRelatedDetail.isInterestRebateAllowed();
}
public BigDecimal getDefaultNominalInterestRatePerPeriod() {
return this.loanProductRelatedDetail.getNominalInterestRatePerPeriod();
}
@@ -57,12 +57,6 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
@Column(name = "amortization_method_enum", nullable = false)
private AmortizationMethod amortizationMethod;
@Column(name = "flexible_repayment_schedule", nullable = false)
private boolean flexibleRepaymentSchedule;
@Column(name = "interest_rebate", nullable = false)
private boolean interestRebateAllowed;
@Column(name = "arrearstolerance_amount", scale = 6, precision = 19, nullable = false)
private BigDecimal inArrearsTolerance;
@@ -78,9 +72,6 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
this.numberOfRepayments = null;
this.amortizationMethod = null;
this.inArrearsTolerance = null;
this.flexibleRepaymentSchedule = false;
this.interestRebateAllowed = false;
}
public LoanProductRelatedDetail(final MonetaryCurrency currency,
@@ -107,8 +98,6 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
this.numberOfRepayments = defaultNumberOfRepayments;
this.amortizationMethod = amortizationMethod;
this.inArrearsTolerance = inArrearsTolerance;
this.flexibleRepaymentSchedule = false;
this.interestRebateAllowed = false;
}
public MonetaryCurrency getCurrency() {
@@ -162,14 +151,6 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
return amortizationMethod;
}
public boolean isFlexibleRepaymentSchedule() {
return flexibleRepaymentSchedule;
}
public boolean isInterestRebateAllowed() {
return interestRebateAllowed;
}
public void update(final LoanProductCommand command) {
Integer digitsAfterDecimalChanged = this.currency.getDigitsAfterDecimal();
@@ -0,0 +1,27 @@
package org.mifosng.platform.loan.domain;
import java.util.List;
import org.mifosng.platform.currency.domain.MonetaryCurrency;
import org.mifosng.platform.currency.domain.Money;
/**
* A wrapper around loan schedule related data exposing needed behaviour by loan.
*
* This wrapper should be side-effect free. It should not attempt to change state of loan parts passed through to it.
*/
public class LoanScheduleWrapper {
public Money calculateTotalOutstanding(
final MonetaryCurrency currency,
final List<LoanRepaymentScheduleInstallment> installments) {
Money cumulativeValue = Money.zero(currency);
for (LoanRepaymentScheduleInstallment scheduledRepayment : installments) {
cumulativeValue = cumulativeValue.plus(scheduledRepayment.getTotalOutstanding(currency));
}
return cumulativeValue;
}
}
@@ -1,17 +1,9 @@
package org.mifosng.platform.loan.service;
import org.joda.time.LocalDate;
import org.mifosng.platform.api.LoanScheduleData;
import org.mifosng.platform.api.commands.CalculateLoanScheduleCommand;
public interface CalculationPlatformService {
LoanScheduleData calculateLoanScheduleNew(CalculateLoanScheduleCommand command);
/**
* Not used at present from application.
*
* was a requirement from creocore that got into early prototye.
*/
LoanPayoffReadModel calculatePayoffOn(Long valueOf, LocalDate payoffDate);
}
@@ -2,21 +2,13 @@ package org.mifosng.platform.loan.service;
import java.util.Set;
import org.joda.time.LocalDate;
import org.mifosng.platform.api.LoanScheduleData;
import org.mifosng.platform.api.commands.CalculateLoanScheduleCommand;
import org.mifosng.platform.api.data.CurrencyData;
import org.mifosng.platform.api.data.MoneyData;
import org.mifosng.platform.currency.domain.ApplicationCurrency;
import org.mifosng.platform.currency.domain.ApplicationCurrencyRepository;
import org.mifosng.platform.exceptions.CurrencyNotFoundException;
import org.mifosng.platform.exceptions.LoanNotFoundException;
import org.mifosng.platform.loan.domain.InterestMethod;
import org.mifosng.platform.loan.domain.Loan;
import org.mifosng.platform.loan.domain.LoanCharge;
import org.mifosng.platform.loan.domain.LoanPayoffSummary;
import org.mifosng.platform.loan.domain.LoanProductRelatedDetail;
import org.mifosng.platform.loan.domain.LoanRepository;
import org.mifosng.platform.loan.domain.PeriodFrequencyType;
import org.mifosng.platform.loanschedule.domain.DefaultLoanScheduleGeneratorFactory;
import org.mifosng.platform.loanschedule.domain.LoanScheduleGenerator;
@@ -29,7 +21,6 @@ import org.springframework.stereotype.Service;
public class CalculationPlatformServiceImpl implements CalculationPlatformService {
private final LoanScheduleGeneratorFactory loanScheduleFactory;
private final LoanRepository loanRepository;
private final ApplicationCurrencyRepository applicationCurrencyRepository;
private final PlatformSecurityContext context;
private final LoanProductRelatedDetailAssembler loanProductRelatedDetailAssembler;
@@ -38,12 +29,10 @@ public class CalculationPlatformServiceImpl implements CalculationPlatformServic
@Autowired
public CalculationPlatformServiceImpl(
final PlatformSecurityContext context,
final LoanRepository loanRepository,
final ApplicationCurrencyRepository applicationCurrencyRepository,
final LoanProductRelatedDetailAssembler loanProductRelatedDetailAssembler,
final LoanChargeAssembler loanChargeAssembler) {
this.context = context;
this.loanRepository = loanRepository;
this.applicationCurrencyRepository = applicationCurrencyRepository;
this.loanScheduleFactory = new DefaultLoanScheduleGeneratorFactory();
this.loanProductRelatedDetailAssembler = loanProductRelatedDetailAssembler;
@@ -76,49 +65,4 @@ public class CalculationPlatformServiceImpl implements CalculationPlatformServic
command.getRepaymentsStartingFromDate(),
command.getInterestChargedFromDate(), loanCharges);
}
/**
* @deprecated functionality from early prototype work with creocore
*/
@Deprecated
@Override
public LoanPayoffReadModel calculatePayoffOn(final Long loanId, final LocalDate payoffDate) {
final Loan loan = this.loanRepository.findOne(loanId);
if (loan == null) {
throw new LoanNotFoundException(loanId);
}
final LoanPayoffSummary payoffSummary = loan.getPayoffSummaryOn(payoffDate);
final String currencyCode = payoffSummary.getTotalPaidToDate().getCurrencyCode();
ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneByCode(currencyCode);
if (applicationCurrency == null) {
throw new CurrencyNotFoundException(currencyCode);
}
final int currencyDigitsAfterDecimal = payoffSummary.getTotalPaidToDate().getCurrencyDigitsAfterDecimal();
CurrencyData currency = new CurrencyData(currencyCode, applicationCurrency.getName(), currencyDigitsAfterDecimal, applicationCurrency.getDisplaySymbol(), applicationCurrency.getNameCode());
MoneyData totalPaidToDate = MoneyData.of(currency, payoffSummary.getTotalPaidToDate()
.getAmount());
MoneyData totalInterestOutstandingBasedOnExpectedMaturityDate = MoneyData.of(currency, payoffSummary.getTotalOutstandingBasedOnExpectedMaturityDate()
.getAmount());
MoneyData totalInterestOutstandingBasedOnPayoffDate = MoneyData.of(currency, payoffSummary.getTotalOutstandingBasedOnPayoffDate()
.getAmount());
MoneyData interestRebateOwed = MoneyData.of(currency, payoffSummary.getRebateOwed().getAmount());
return new LoanPayoffReadModel(payoffSummary.getReference().toString(),
payoffSummary.getAcutalDisbursementDate(),
payoffSummary.getExpectedMaturityDate(),
payoffSummary.getProjectedMaturityDate(),
payoffSummary.getExpectedLoanTermInDays(),
payoffSummary.getProjectedLoanTermInDays(), totalPaidToDate,
totalInterestOutstandingBasedOnExpectedMaturityDate,
totalInterestOutstandingBasedOnPayoffDate, interestRebateOwed);
}
}
@@ -1,136 +0,0 @@
package org.mifosng.platform.loan.service;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormatter;
import org.mifosng.platform.api.data.MoneyData;
/**
*
*/
public class LoanPayoffReadModel {
private String reference;
private String acutalDisbursementDate;
private String expectedMaturityDate;
private String projectedMaturityDate;
private Integer expectedLoanTermInDays;
private Integer projectedLoanTermInDays;
private MoneyData totalPaidToDate;
private MoneyData totalOutstandingBasedOnExpectedMaturityDate;
private MoneyData totalOutstandingBasedOnPayoffDate;
private MoneyData interestRebateOwed;
protected LoanPayoffReadModel() {
//
}
public LoanPayoffReadModel(
final String reference,
final LocalDate acutalDisbursementDate,
final LocalDate expectedMaturityDate,
final LocalDate projectedMaturityDate,
final Integer expectedLoanTermInDays,
final Integer projectedLoanTermInDays,
final MoneyData totalPaidToDate,
final MoneyData totalOutstandingBasedOnExpectedMaturityDate,
final MoneyData totalOutstandingBasedOnPayoffDate,
final MoneyData interestRebateOwed) {
this.reference = reference;
DateTimeFormatter formatter = org.joda.time.format.DateTimeFormat
.forPattern("yyyy-MM-dd");
this.acutalDisbursementDate = formatter.print(acutalDisbursementDate);
this.expectedMaturityDate = formatter.print(expectedMaturityDate);
this.projectedMaturityDate = formatter.print(projectedMaturityDate);
this.expectedLoanTermInDays = expectedLoanTermInDays;
this.projectedLoanTermInDays = projectedLoanTermInDays;
this.totalPaidToDate = totalPaidToDate;
this.totalOutstandingBasedOnExpectedMaturityDate = totalOutstandingBasedOnExpectedMaturityDate;
this.totalOutstandingBasedOnPayoffDate = totalOutstandingBasedOnPayoffDate;
this.interestRebateOwed = interestRebateOwed;
}
public String getReference() {
return this.reference;
}
public void setReference(final String reference) {
this.reference = reference;
}
public String getAcutalDisbursementDate() {
return this.acutalDisbursementDate;
}
public void setAcutalDisbursementDate(final String acutalDisbursementDate) {
this.acutalDisbursementDate = acutalDisbursementDate;
}
public String getExpectedMaturityDate() {
return this.expectedMaturityDate;
}
public void setExpectedMaturityDate(final String expectedMaturityDate) {
this.expectedMaturityDate = expectedMaturityDate;
}
public String getProjectedMaturityDate() {
return this.projectedMaturityDate;
}
public void setProjectedMaturityDate(final String projectedMaturityDate) {
this.projectedMaturityDate = projectedMaturityDate;
}
public Integer getExpectedLoanTermInDays() {
return this.expectedLoanTermInDays;
}
public void setExpectedLoanTermInDays(final Integer expectedLoanTermInDays) {
this.expectedLoanTermInDays = expectedLoanTermInDays;
}
public Integer getProjectedLoanTermInDays() {
return this.projectedLoanTermInDays;
}
public void setProjectedLoanTermInDays(final Integer projectedLoanTermInDays) {
this.projectedLoanTermInDays = projectedLoanTermInDays;
}
public MoneyData getTotalPaidToDate() {
return this.totalPaidToDate;
}
public void setTotalPaidToDate(final MoneyData totalPaidToDate) {
this.totalPaidToDate = totalPaidToDate;
}
public MoneyData getInterestRebateOwed() {
return this.interestRebateOwed;
}
public void setInterestRebateOwed(final MoneyData interestRebateOwed) {
this.interestRebateOwed = interestRebateOwed;
}
public MoneyData getTotalOutstandingBasedOnExpectedMaturityDate() {
return this.totalOutstandingBasedOnExpectedMaturityDate;
}
public void setTotalOutstandingBasedOnExpectedMaturityDate(
final MoneyData totalOutstandingBasedOnExpectedMaturityDate) {
this.totalOutstandingBasedOnExpectedMaturityDate = totalOutstandingBasedOnExpectedMaturityDate;
}
public MoneyData getTotalOutstandingBasedOnPayoffDate() {
return this.totalOutstandingBasedOnPayoffDate;
}
public void setTotalOutstandingBasedOnPayoffDate(
final MoneyData totalOutstandingBasedOnPayoffDate) {
this.totalOutstandingBasedOnPayoffDate = totalOutstandingBasedOnPayoffDate;
}
}
@@ -189,13 +189,21 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final boolean waitingForDisbursal = (loanBasicDetails.getStatus().getId().equals(200L));
final boolean isActive = (loanBasicDetails.getStatus().getId().equals(300L));
final boolean closedObligationsMet = (loanBasicDetails.getStatus().getId().equals(600L));
final boolean closedWrittenOff = (loanBasicDetails.getStatus().getId().equals(602L));
final boolean closedRescheduled = (loanBasicDetails.getStatus().getId().equals(602L));
final boolean closed = closedObligationsMet || closedWrittenOff || closedRescheduled;
final boolean isOverpaid = (loanBasicDetails.getStatus().getId().equals(700L));
final boolean addLoanChargeAllowed = !closedObligationsMet || !isOverpaid;
boolean addLoanChargeAllowed = true;
if (closed || isOverpaid) {
addLoanChargeAllowed = false;
}
final boolean waiveAllowed = isWaiverAllowed && isActive;
final boolean makeRepaymentAllowed = isActive;
final boolean closeLoanAllowed = !closedObligationsMet;
final boolean closeLoanAsRescheduledAllowed = !closedObligationsMet && !isOverpaid;
final boolean closeLoanAllowed = !closed && isActive;
final boolean closeLoanAsRescheduledAllowed = !closed && !isOverpaid && isActive;
final boolean rejectAllowed = pendingApproval;
final boolean withdrawnByApplicantAllowed = waitingForDisbursal
@@ -647,7 +647,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
throw new ChargeIsNotActiveException(chargeDefinition.getId());
}
if (!loan.getCurrency().getCode().equals(chargeDefinition.getCurrencyCode())){
if (!loan.hasCurrencyCodeOf(chargeDefinition.getCurrencyCode())){
String errorMessage = "Charge and Loan must have the same currency.";
throw new InvalidCurrencyException("charge", "attach.to.loan", errorMessage);
}
@@ -152,7 +152,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
public String loanProductSchema() {
return "lp.id as id, lp.fund_id as fundId, f.name as fundName, lp.loan_transaction_strategy_id as transactionStrategyId, ltps.name as transactionStrategyName, "
+ "lp.name as name, lp.description as description, lp.flexible_repayment_schedule as isFlexible, lp.interest_rebate as isInterestRebateAllowed, "
+ "lp.name as name, lp.description as description, "
+ "lp.principal_amount as principal, lp.currency_code as currencyCode, lp.currency_digits as currencyDigits, "
+ "lp.nominal_interest_rate_per_period as interestRatePerPeriod, lp.interest_period_frequency_enum as interestRatePerPeriodFreq, "
+ "lp.annual_nominal_interest_rate as annualInterestRate, lp.interest_method_enum as interestMethod, lp.interest_calculated_in_period_enum as interestCalculationInPeriodMethod,"