diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/AbstractLoanRepaymentScheduleTransactionProcessor.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/AbstractLoanRepaymentScheduleTransactionProcessor.java
index a6e62ea25..7412242bc 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/AbstractLoanRepaymentScheduleTransactionProcessor.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/AbstractLoanRepaymentScheduleTransactionProcessor.java
@@ -60,18 +60,27 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
handleTransaction(loanTransaction, currency, installments, charges);
} else {
/**
- * reverse existing transactions and create new transactions
- * in their Lieu
+ * For existing transactions, check if the re-payment
+ * breakup (principal, interest, fees, penalties) has
+ * changed.
**/
LoanTransaction newLoanTransaction = LoanTransaction.copyTransactionProperties(loanTransaction);
- // Reverse the original loan transaction
- loanTransaction.reverse();
- changedTransactionDetail.getReversedTransactions().add(loanTransaction);
- // Reset derived component of new loan transaction
+ // Reset derived component of new loan transaction and
+ // re-process transaction
newLoanTransaction.resetDerivedComponents();
- changedTransactionDetail.getNewTransactions().add(newLoanTransaction);
handleTransaction(newLoanTransaction, currency, installments, charges);
+
+ /**
+ * Check if the transaction amounts have changed. If so,
+ * reverse the original transaction and update
+ * changedTransactionDetail accordingly
+ **/
+ if (!LoanTransaction.transactionAmountsMatch(currency, loanTransaction, newLoanTransaction)) {
+ loanTransaction.reverse();
+ changedTransactionDetail.getReversedTransactions().add(loanTransaction);
+ changedTransactionDetail.getNewTransactions().add(newLoanTransaction);
+ }
}
} else if (loanTransaction.isWriteOff()) {
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/ChangedTransactionDetail.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/ChangedTransactionDetail.java
index db73b3ec0..576fb115c 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/ChangedTransactionDetail.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/ChangedTransactionDetail.java
@@ -3,6 +3,12 @@ package org.mifosplatform.portfolio.loanaccount.domain;
import java.util.ArrayList;
import java.util.List;
+/**
+ * Stores details of {@link LoanTransaction}'s that were reversed or newly
+ * created
+ *
+ *
+ */
public class ChangedTransactionDetail {
private List newTransactions = new ArrayList();
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java
index 50e0e23c2..72fd18df4 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java
@@ -520,6 +520,14 @@ public class Loan extends AbstractPersistable {
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
.determineProcessor(this.transactionProcessingStrategy);
if (!loanCharge.isDueAtDisbursement() && loanCharge.isPaidOrPartiallyPaid(loanCurrency())) {
+ /****
+ * TODO Vishwas Currently we do not allow removing a loan charge
+ * after a loan is approved (hence there is no need to adjust any
+ * loan transactions).
+ *
+ * Consider removing this block of code or logically completing it
+ * for the future by getting the list of affected Transactions
+ ***/
final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement,
getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
@@ -570,6 +578,14 @@ public class Loan extends AbstractPersistable {
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
.determineProcessor(this.transactionProcessingStrategy);
if (!loanCharge.isDueAtDisbursement()) {
+ /****
+ * TODO Vishwas Currently we do not allow waiving updating loan
+ * charge after a loan is approved (hence there is no need to adjust
+ * any loan transactions).
+ *
+ * Consider removing this block of code or logically completing it
+ * for the future by getting the list of affected Transactions
+ ***/
final List allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement,
getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
@@ -619,7 +635,7 @@ public class Loan extends AbstractPersistable {
.determineProcessor(this.transactionProcessingStrategy);
if (!loanCharge.isDueAtDisbursement() && loanCharge.isPaidOrPartiallyPaid(loanCurrency())) {
/****
- * TODO vishwas Currently we do not allow waiving fully paid loan
+ * TODO Vishwas Currently we do not allow waiving fully paid loan
* charge and waiving partially paid loan charges only waives the
* remaining amount.
*
@@ -717,6 +733,15 @@ public class Loan extends AbstractPersistable {
// if the loan application/contract is modified when repayments are
// already against it - then need to re-process it
+
+ /****
+ * TODO Vishwas Currently we do not allow modifying a Loan contract once
+ * the loan is approved (hence there is no need to adjust any loan
+ * transactions).
+ *
+ * Consider removing this block of code or logically completing it for
+ * the future by getting the list of affected Transactions
+ ***/
final List repaymentsOrWaivers = retreiveListOfTransactionsPostDisbursement();
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
@@ -1390,21 +1415,17 @@ public class Loan extends AbstractPersistable {
updateLoanSummaryDerivedFields();
}
- public LoanTransaction waiveInterest(final JsonCommand command, final LoanLifecycleStateMachine loanLifecycleStateMachine,
- final List existingTransactionIds, final List existingReversedTransactionIds) {
-
- final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
- final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
-
- final Money amountToWaive = Money.of(loanCurrency(), transactionAmount);
- final LoanTransaction waiveInterestTransaction = LoanTransaction.waiver(this, amountToWaive, transactionDate);
+ public ChangedTransactionDetail waiveInterest(final LoanTransaction waiveInterestTransaction,
+ final LoanLifecycleStateMachine loanLifecycleStateMachine, final List existingTransactionIds,
+ final List existingReversedTransactionIds) {
existingTransactionIds.addAll(findExistingTransactionIds());
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
- handleRepaymentOrWaiverTransaction(waiveInterestTransaction, loanLifecycleStateMachine, null);
+ ChangedTransactionDetail changedTransactionDetail = handleRepaymentOrWaiverTransaction(waiveInterestTransaction,
+ loanLifecycleStateMachine, null);
- return waiveInterestTransaction;
+ return changedTransactionDetail;
}
public ChangedTransactionDetail makeRepayment(final LoanTransaction repaymentTransaction,
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java
index 9b4dbe03d..698f2b273 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java
@@ -100,6 +100,16 @@ public final class LoanTransaction extends AbstractPersistable {
return applyCharge;
}
+ public static boolean transactionAmountsMatch(MonetaryCurrency currency, LoanTransaction loanTransaction,
+ LoanTransaction newLoanTransaction) {
+ if (loanTransaction.getAmount(currency).isEqualTo(newLoanTransaction.getAmount(currency))
+ && (loanTransaction.getPrincipalPortion(currency).isEqualTo(newLoanTransaction.getPrincipalPortion(currency)))
+ && (loanTransaction.getInterestPortion(currency).isEqualTo(newLoanTransaction.getInterestPortion(currency)))
+ && (loanTransaction.getFeeChargesPortion(currency).isEqualTo(newLoanTransaction.getFeeChargesPortion(currency)))
+ && (loanTransaction.getPenaltyChargesPortion(currency).isEqualTo(newLoanTransaction.getPenaltyChargesPortion(currency)))) { return true; }
+ return false;
+ }
+
private LoanTransaction(Loan loan, Integer typeOf, Date dateOf, BigDecimal amount, BigDecimal principalPortion,
BigDecimal interestPortion, BigDecimal feeChargesPortion, BigDecimal penaltyChargesPortion, boolean reversed) {
super();
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
index 147b92751..3bf6e86d5 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
@@ -292,8 +292,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
* TODO Vishwas Batch save is giving me a
* HibernateOptimisticLockingFailureException, looping and saving for
* the time being, not a major issue for now as this loop is entered
- * only in edge cases (when a payment is made before the latest payment
- * recorded against the loan)
+ * only in edge cases (when a adjustment is made before the latest
+ * payment recorded against the loan)
***/
if (changedTransactionDetail != null) {
for (LoanTransaction loanTransaction : changedTransactionDetail.getNewTransactions()) {
@@ -336,21 +336,41 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
changes.put("transactionAmount", command.stringValueOfParameterNamed("transactionAmount"));
changes.put("locale", command.locale());
changes.put("dateFormat", command.dateFormat());
+ final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
+ final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
final Loan loan = retrieveLoanBy(loanId);
final List existingTransactionIds = new ArrayList();
final List existingReversedTransactionIds = new ArrayList();
- final LoanTransaction waiveTransaction = loan.waiveInterest(command, defaultLoanLifecycleStateMachine(), existingTransactionIds,
- existingReversedTransactionIds);
- this.loanTransactionRepository.save(waiveTransaction);
+ final Money transactionAmountAsMoney = Money.of(loan.getCurrency(), transactionAmount);
+ LoanTransaction waiveInterestTransaction = LoanTransaction.waiver(loan, transactionAmountAsMoney, transactionDate);
+
+ final ChangedTransactionDetail changedTransactionDetail = loan.waiveInterest(waiveInterestTransaction,
+ defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds);
+
+ this.loanTransactionRepository.save(waiveInterestTransaction);
+
+ /***
+ * TODO Vishwas Batch save is giving me a
+ * HibernateOptimisticLockingFailureException, looping and saving for
+ * the time being, not a major issue for now as this loop is entered
+ * only in edge cases (when a waiver is made before the latest payment
+ * recorded against the loan)
+ ***/
+ if (changedTransactionDetail != null) {
+ for (LoanTransaction loanTransaction : changedTransactionDetail.getNewTransactions()) {
+ this.loanTransactionRepository.save(loanTransaction);
+ }
+ }
+
this.loanRepository.save(loan);
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
changes.put("note", noteText);
- final Note note = Note.loanTransactionNote(loan, waiveTransaction, noteText);
+ final Note note = Note.loanTransactionNote(loan, waiveInterestTransaction, noteText);
this.noteRepository.save(note);
}
@@ -358,7 +378,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
- .withEntityId(waiveTransaction.getId()) //
+ .withEntityId(waiveInterestTransaction.getId()) //
.withOfficeId(loan.getOfficeId()) //
.withClientId(loan.getClientId()) //
.withGroupId(loan.getGroupId()) //