MIFOSX-888 - Early Repayments Strategy

This commit is contained in:
Vishwas Babu A J
2014-02-03 15:41:04 +01:00
committed by Sander van der Heyden
parent 2e5c9b6eae
commit f09cf9a433
5 changed files with 180 additions and 5 deletions
+30 -5
View File
@@ -2503,7 +2503,7 @@ GET https://DomainName/api/v1/clients/{clientId}
<br>
<div class=apiClick>clients?offset=10&limit=50</div>
<br>
<div class=apiClick>clients?orderBy=displayName,sortOrder=DESC</div>
<div class=apiClick>clients?orderBy=displayName&sortOrder=DESC</div>
</div>
<div class="method-example">
<code class="method-declaration">
@@ -3663,7 +3663,7 @@ GET https://DomainName/mifosng-provider/api/v1/centers/9?associations=groupMembe
<br>
<div class=apiClick>centers?offset=10&limit=50</div>
<br>
<div class=apiClick>centers?orderBy=name,sortOrder=DESC</div>
<div class=apiClick>centers?orderBy=name&sortOrder=DESC</div>
</div>
<div class="method-example">
<code class="method-declaration">
@@ -4579,7 +4579,7 @@ DELETE groups/2
<br>
<div class=apiClick>groups?offset=10&limit=50</div>
<br>
<div class=apiClick>groups?orderBy=name,sortOrder=DESC</div>
<div class=apiClick>groups?orderBy=name&sortOrder=DESC</div>
</div>
<div class="method-example">
<code class="method-declaration">
@@ -4820,6 +4820,9 @@ An enumeration that indicates the type of transaction processing strategy to be
<li>4 = RBI (India)</li>
<li>5 = Principal Interest Penalties Fees Order</li>
<li>6 = Interest Principal Penalties Fees Order</li>
<li>7 = Early Payment Strategy</li>
</ul>
</ul>
</td>
</tr>
@@ -5473,7 +5476,7 @@ GET https://DomainName/api/v1/loans/{loanId}
<br>
<div class=apiClick>loans?offset=10&limit=50</div>
<br>
<div class=apiClick>loans?orderBy=accountNo,sortOrder=DESC</div>
<div class=apiClick>loans?orderBy=accountNo&sortOrder=DESC</div>
</div>
<div class="method-example">
<code class="method-declaration">
@@ -8048,6 +8051,7 @@ An enumeration that indicates the type of transaction processing strategy to be
<li>4 = RBI (India)</li>
<li>5 = Principal Interest Penalties Fees Order</li>
<li>6 = Interest Principal Penalties Fees Order</li>
<li>7 = Early Payment Strategy</li>
</ul>
</td>
</tr>
@@ -20454,7 +20458,7 @@ No Request Body:
<br>
<div class=apiClick>journalentries?offset=10&limit=50</div>
<br>
<div class=apiClick>journalentries?orderBy=transactionId,sortOrder=DESC</div>
<div class=apiClick>journalentries?orderBy=transactionId&sortOrder=DESC</div>
<br>
<div class=apiClick>journalentries?runningBalance=true</div>
<br>
@@ -22702,6 +22706,27 @@ No Request Body:
<p><strong>On time payment</strong>: Any payment that pays off an installment that occurs exactly on the due date of the installment.</p>
<p><strong>Late payment</strong>: Any payment that pays off an installment that occurs after the due date of the installment. There is no penalization for late payment. The total cost of the loan does not automatically increase, no penalties are automatically applied to the loan.</p>
<h4>Early Payment Strategy</h4>
<p>This strategy works similar to the Interest Principal Penalties Fees Order for on-time and late payments. If the installments are paid early we will </p>
<p>
<strong>Payment order</strong>:
<ol>
<li>Overdue and due interest</li>
<li>Overdue and due principal</li>
<li>Overdue and due penalties</li>
<li>Overdue and due fees</li>
</ol>
</p>
<p><strong>Early payment</strong>: Any payment that pays off an installment that occurs before the due date of the installment. There is no incentive/advantage to making an early payment as theres no decrease in cost of the loan.</p>
<p><strong>On time payment</strong>: Any payment that pays off an installment that occurs exactly on the due date of the installment.</p>
<p><strong>Late payment</strong>: Any payment that pays off an installment that occurs after the due date of the installment. There is no penalization for late payment. The total cost of the loan does not automatically increase, no penalties are automatically applied to the loan.</p>
</div>
<!-- end of page-wrapper div -->
@@ -0,0 +1,3 @@
INSERT INTO `ref_loan_transaction_processing_strategy` ( `code`, `name`)
VALUES
( 'early-repayment-strategy', 'Early Repayment Strategy');
@@ -12,6 +12,7 @@ import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.impl.
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.impl.MifosStyleLoanRepaymentScheduleTransactionProcessor;
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.impl.PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor;
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.impl.RBILoanRepaymentScheduleTransactionProcessor;
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.impl.EarlyPaymentLoanRepaymentScheduleTransactionProcessor;
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
import org.springframework.stereotype.Component;
@@ -32,6 +33,10 @@ public class LoanRepaymentScheduleTransactionProcessorFactory {
if (transactionProcessingStrategy.isHeavensfamilyStrategy()) {
processor = new HeavensFamilyLoanRepaymentScheduleTransactionProcessor();
}
if (transactionProcessingStrategy.isEarlyPaymentStrategy()) {
processor = new EarlyPaymentLoanRepaymentScheduleTransactionProcessor();
}
if (transactionProcessingStrategy.isCreocoreStrategy()) {
processor = new CreocoreLoanRepaymentScheduleTransactionProcessor();
@@ -0,0 +1,138 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.impl;
import java.util.List;
import org.joda.time.LocalDate;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.AbstractLoanRepaymentScheduleTransactionProcessor;
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
/**
* This {@link LoanRepaymentScheduleTransactionProcessor} defaults to having the
* payment order of Interest first, then principal, penalties and fees.
*/
public class EarlyPaymentLoanRepaymentScheduleTransactionProcessor extends
AbstractLoanRepaymentScheduleTransactionProcessor {
/**
* For early/'in advance' repayments, pay off in the same way as on-time
* payments, interest first, principal, penalties and charges.
*/
@Override
protected Money handleTransactionThatIsPaymentInAdvanceOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
final List<LoanRepaymentScheduleInstallment> installments, final LoanTransaction loanTransaction,
final LocalDate transactionDate, final Money paymentInAdvance) {
final MonetaryCurrency currency = paymentInAdvance.getCurrency();
Money transactionAmountRemaining = paymentInAdvance;
Money principalPortion = Money.zero(transactionAmountRemaining.getCurrency());
Money interestPortion = Money.zero(transactionAmountRemaining.getCurrency());
Money feeChargesPortion = Money.zero(transactionAmountRemaining.getCurrency());
Money penaltyChargesPortion = Money.zero(transactionAmountRemaining.getCurrency());
if (loanTransaction.isChargesWaiver()) {
// zero this type of transaction and ignore it for now.
transactionAmountRemaining = Money.zero(currency);
} else if (loanTransaction.isInterestWaiver()) {
interestPortion = currentInstallment.waiveInterestComponent(transactionDate, transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
} else if (loanTransaction.isChargePayment()) {
if (loanTransaction.isPenaltyPayment()) {
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
} else {
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionDate, transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
}
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
} else {
// Only allocate to principal:
principalPortion = currentInstallment.payPrincipalComponent(transactionDate, transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(principalPortion);
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
}
return transactionAmountRemaining;
}
/**
* For late repayments, pay off in the same way as on-time payments,
* interest first then principal.
*/
@Override
protected Money handleTransactionThatIsALateRepaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
final List<LoanRepaymentScheduleInstallment> installments, final LoanTransaction loanTransaction,
final Money transactionAmountUnprocessed) {
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, transactionAmountUnprocessed);
}
/**
* For normal on-time repayments, pays off interest first, then principal.
*/
@Override
protected Money handleTransactionThatIsOnTimePaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed) {
final LocalDate transactionDate = loanTransaction.getTransactionDate();
final MonetaryCurrency currency = transactionAmountUnprocessed.getCurrency();
Money transactionAmountRemaining = transactionAmountUnprocessed;
Money principalPortion = Money.zero(transactionAmountRemaining.getCurrency());
Money interestPortion = Money.zero(transactionAmountRemaining.getCurrency());
Money feeChargesPortion = Money.zero(transactionAmountRemaining.getCurrency());
Money penaltyChargesPortion = Money.zero(transactionAmountRemaining.getCurrency());
if (loanTransaction.isChargesWaiver()) {
// zero this type of transaction and ignore it for now.
transactionAmountRemaining = Money.zero(currency);
} else if (loanTransaction.isInterestWaiver()) {
interestPortion = currentInstallment.waiveInterestComponent(transactionDate, transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
} else if (loanTransaction.isChargePayment()) {
if (loanTransaction.isPenaltyPayment()) {
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
} else {
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionDate, transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
}
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
} else {
interestPortion = currentInstallment.payInterestComponent(transactionDate, transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
principalPortion = currentInstallment.payPrincipalComponent(transactionDate, transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(principalPortion);
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionDate, transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
}
return transactionAmountRemaining;
}
}
@@ -37,6 +37,10 @@ public class LoanTransactionProcessingStrategy extends AbstractPersistable<Long>
public boolean isHeavensfamilyStrategy() {
return "heavensfamily-strategy".equalsIgnoreCase(this.code);
}
public boolean isEarlyPaymentStrategy() {
return "early-payment-strategy".equalsIgnoreCase(this.code);
}
public boolean isCreocoreStrategy() {
return "creocore-strategy".equalsIgnoreCase(this.code);