This is an automated email from the ASF dual-hosted git repository.
adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new 59c5ad450 FINERACT-1724: Refactor loan repayment transaction processor
59c5ad450 is described below
commit 59c5ad45003254accc62ed4c71941d5d83138f39
Author: Adam Saghy <[email protected]>
AuthorDate: Wed Aug 30 11:55:36 2023 +0200
FINERACT-1724: Refactor loan repayment transaction processor
---
.../portfolio/loanaccount/domain/Loan.java | 61 +--
.../LoanRepaymentScheduleTransactionProcessor.java | 29 +-
...tLoanRepaymentScheduleTransactionProcessor.java | 408 +++++++--------------
...dvancedPaymentScheduleTransactionProcessor.java | 21 ++
...eLoanRepaymentScheduleTransactionProcessor.java | 18 -
...tLoanRepaymentScheduleTransactionProcessor.java | 5 -
...eLoanRepaymentScheduleTransactionProcessor.java | 5 -
...eLoanRepaymentScheduleTransactionProcessor.java | 22 +-
...yLoanRepaymentScheduleTransactionProcessor.java | 3 -
...ILoanRepaymentScheduleTransactionProcessor.java | 19 -
.../domain/AbstractLoanScheduleGenerator.java | 4 +-
.../LoanChargeWritePlatformServiceImpl.java | 4 +-
12 files changed, 213 insertions(+), 386 deletions(-)
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index 72eb5fe8d..d6756550e 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
@@ -702,7 +702,7 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
final LoanRepaymentScheduleTransactionProcessor
loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
.determineProcessor(this.transactionProcessingStrategyCode);
final List<LoanTransaction> allNonContraTransactionsPostDisbursement =
retrieveListOfTransactionsPostDisbursement();
- changedTransactionDetail =
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
+ changedTransactionDetail =
loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(getDisbursementDate(),
allNonContraTransactionsPostDisbursement, getCurrency(),
getRepaymentScheduleInstallments(), getActiveCharges());
for (final Map.Entry<Long, LoanTransaction> mapEntry :
changedTransactionDetail.getNewTransactionMappings().entrySet()) {
@@ -789,7 +789,8 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
}
final Set<LoanCharge> loanCharges = new HashSet<>(1);
loanCharges.add(charge);
-
loanRepaymentScheduleTransactionProcessor.handleTransaction(chargesPayment,
getCurrency(), chargePaymentInstallments, loanCharges);
+
loanRepaymentScheduleTransactionProcessor.processLatestTransaction(chargesPayment,
getCurrency(), chargePaymentInstallments,
+ loanCharges, getTotalOverpaidAsMoney());
updateLoanSummaryDerivedFields();
doPostLoanTransactionChecks(chargesPayment.getTransactionDate(),
loanLifecycleStateMachine);
@@ -862,8 +863,8 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
* affected Transactions
***/
final List<LoanTransaction>
allNonContraTransactionsPostDisbursement =
retrieveListOfTransactionsPostDisbursement();
-
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
allNonContraTransactionsPostDisbursement,
- getCurrency(), getRepaymentScheduleInstallments(),
getActiveCharges());
+
loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(getDisbursementDate(),
+ allNonContraTransactionsPostDisbursement, getCurrency(),
getRepaymentScheduleInstallments(), getActiveCharges());
}
this.charges.remove(loanCharge);
updateLoanSummaryDerivedFields();
@@ -930,8 +931,8 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
* affected Transactions
***/
final List<LoanTransaction>
allNonContraTransactionsPostDisbursement =
retrieveListOfTransactionsPostDisbursement();
-
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
allNonContraTransactionsPostDisbursement,
- getCurrency(), getRepaymentScheduleInstallments(),
getActiveCharges());
+
loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(getDisbursementDate(),
+ allNonContraTransactionsPostDisbursement, getCurrency(),
getRepaymentScheduleInstallments(), getActiveCharges());
} else {
// reprocess loan schedule based on charge been waived.
final LoanRepaymentScheduleProcessingWrapper wrapper = new
LoanRepaymentScheduleProcessingWrapper();
@@ -1123,8 +1124,8 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
* affected Transactions
***/
final List<LoanTransaction>
allNonContraTransactionsPostDisbursement =
retrieveListOfTransactionsPostDisbursement();
-
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
allNonContraTransactionsPostDisbursement,
- getCurrency(), getRepaymentScheduleInstallments(),
getActiveCharges());
+
loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(getDisbursementDate(),
+ allNonContraTransactionsPostDisbursement, getCurrency(),
getRepaymentScheduleInstallments(), getActiveCharges());
} else {
// reprocess loan schedule based on charge been waived.
final LoanRepaymentScheduleProcessingWrapper wrapper = new
LoanRepaymentScheduleProcessingWrapper();
@@ -2705,7 +2706,7 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
if (!allNonContraTransactionsPostDisbursement.isEmpty()) {
final LoanRepaymentScheduleTransactionProcessor
loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
.determineProcessor(this.transactionProcessingStrategyCode);
- changedTransactionDetail =
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
+ changedTransactionDetail =
loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(getDisbursementDate(),
allNonContraTransactionsPostDisbursement,
getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
for (final Map.Entry<Long, LoanTransaction> mapEntry :
changedTransactionDetail.getNewTransactionMappings().entrySet()) {
mapEntry.getValue().updateLoan(this);
@@ -3330,8 +3331,8 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
if (isTransactionChronologicallyLatest && adjustedTransaction == null
&& (!reprocess ||
!this.repaymentScheduleDetail().isInterestRecalculationEnabled()) &&
!isForeclosure()) {
-
loanRepaymentScheduleTransactionProcessor.handleTransaction(loanTransaction,
getCurrency(), getRepaymentScheduleInstallments(),
- getActiveCharges());
+
loanRepaymentScheduleTransactionProcessor.processLatestTransaction(loanTransaction,
getCurrency(),
+ getRepaymentScheduleInstallments(), getActiveCharges(),
getTotalOverpaidAsMoney());
reprocess = false;
if
(this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
if (currentInstallment == null ||
currentInstallment.isNotFullyPaidOff()) {
@@ -3350,7 +3351,7 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO);
}
final List<LoanTransaction>
allNonContraTransactionsPostDisbursement =
retrieveListOfTransactionsPostDisbursement();
- changedTransactionDetail =
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
+ changedTransactionDetail =
loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(getDisbursementDate(),
allNonContraTransactionsPostDisbursement, getCurrency(),
getRepaymentScheduleInstallments(), getActiveCharges());
for (final Map.Entry<Long, LoanTransaction> mapEntry :
changedTransactionDetail.getNewTransactionMappings().entrySet()) {
mapEntry.getValue().updateLoan(this);
@@ -3778,7 +3779,7 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO);
}
- ChangedTransactionDetail changedTransactionDetail =
loanRepaymentScheduleTransactionProcessor.handleTransaction(
+ ChangedTransactionDetail changedTransactionDetail =
loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(
getDisbursementDate(),
allNonContraTransactionsPostDisbursement, getCurrency(),
getRepaymentScheduleInstallments(),
getActiveCharges());
updateLoanSummaryDerivedFields();
@@ -3904,7 +3905,8 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
}
addLoanTransaction(loanTransaction);
-
loanRepaymentScheduleTransactionProcessor.handleWriteOff(loanTransaction,
loanCurrency(), getRepaymentScheduleInstallments());
+
loanRepaymentScheduleTransactionProcessor.processLatestTransaction(loanTransaction,
loanCurrency(),
+ getRepaymentScheduleInstallments(), getActiveCharges(),
getTotalOverpaidAsMoney());
updateLoanSummaryDerivedFields();
}
@@ -3926,7 +3928,7 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO);
}
final List<LoanTransaction>
allNonContraTransactionsPostDisbursement =
retrieveListOfTransactionsPostDisbursement();
- changedTransactionDetail =
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
+ changedTransactionDetail =
loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(getDisbursementDate(),
allNonContraTransactionsPostDisbursement, getCurrency(),
getRepaymentScheduleInstallments(), getActiveCharges());
for (final Map.Entry<Long, LoanTransaction> mapEntry :
changedTransactionDetail.getNewTransactionMappings().entrySet()) {
mapEntry.getValue().updateLoan(this);
@@ -4008,8 +4010,8 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
}
addLoanTransaction(loanTransaction);
-
loanRepaymentScheduleTransactionProcessor.handleWriteOff(loanTransaction,
loanCurrency(),
- getRepaymentScheduleInstallments());
+
loanRepaymentScheduleTransactionProcessor.processLatestTransaction(loanTransaction,
loanCurrency(),
+ getRepaymentScheduleInstallments(),
getActiveCharges(), getTotalOverpaidAsMoney());
updateLoanSummaryDerivedFields();
} else if (totalOutstanding.isGreaterThanZero()) {
@@ -5400,7 +5402,7 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
final LoanRepaymentScheduleTransactionProcessor
loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
.determineProcessor(this.transactionProcessingStrategyCode);
final List<LoanTransaction> allNonContraTransactionsPostDisbursement =
retrieveListOfTransactionsPostDisbursement();
- ChangedTransactionDetail changedTransactionDetail =
loanRepaymentScheduleTransactionProcessor.handleTransaction(
+ ChangedTransactionDetail changedTransactionDetail =
loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(
getDisbursementDate(),
allNonContraTransactionsPostDisbursement, getCurrency(),
getRepaymentScheduleInstallments(),
getActiveCharges());
for (final Map.Entry<Long, LoanTransaction> mapEntry :
changedTransactionDetail.getNewTransactionMappings().entrySet()) {
@@ -5478,6 +5480,10 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
return this.totalOverpaid;
}
+ public Money getTotalOverpaidAsMoney() {
+ return Money.of(this.repaymentScheduleDetail().getCurrency(),
this.totalOverpaid);
+ }
+
public LocalDate getOverpaidOnDate() {
return this.overpaidOnDate;
}
@@ -5539,7 +5545,7 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
final LoanRepaymentScheduleTransactionProcessor
loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
.determineProcessor(this.transactionProcessingStrategyCode);
final List<LoanTransaction> allNonContraTransactionsPostDisbursement =
retrieveListOfTransactionsPostDisbursement();
- ChangedTransactionDetail changedTransactionDetail =
loanRepaymentScheduleTransactionProcessor.handleTransaction(
+ ChangedTransactionDetail changedTransactionDetail =
loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(
getDisbursementDate(),
allNonContraTransactionsPostDisbursement, getCurrency(),
getRepaymentScheduleInstallments(),
getActiveCharges());
for (final Map.Entry<Long, LoanTransaction> mapEntry :
changedTransactionDetail.getNewTransactionMappings().entrySet()) {
@@ -5782,7 +5788,7 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
for (LoanTransaction loanTransaction :
allNonContraTransactionsPostDisbursement) {
copyTransactions.add(LoanTransaction.copyTransactionProperties(loanTransaction));
}
-
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
copyTransactions, getCurrency(),
+
loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(getDisbursementDate(),
copyTransactions, getCurrency(),
getRepaymentScheduleInstallments(), getActiveCharges());
updateLoanSummaryDerivedFields();
@@ -6382,11 +6388,11 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
// If is a refund
if (adjustedTransaction == null) {
-
loanRepaymentScheduleTransactionProcessor.handleRefund(loanTransaction,
getCurrency(), getRepaymentScheduleInstallments(),
- getActiveCharges());
+
loanRepaymentScheduleTransactionProcessor.processLatestTransaction(loanTransaction,
getCurrency(),
+ getRepaymentScheduleInstallments(), getActiveCharges(),
getTotalOverpaidAsMoney());
} else {
final List<LoanTransaction>
allNonContraTransactionsPostDisbursement =
retrieveListOfTransactionsPostDisbursement();
- changedTransactionDetail =
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
+ changedTransactionDetail =
loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(getDisbursementDate(),
allNonContraTransactionsPostDisbursement, getCurrency(),
getRepaymentScheduleInstallments(), getActiveCharges());
for (final Map.Entry<Long, LoanTransaction> mapEntry :
changedTransactionDetail.getNewTransactionMappings().entrySet()) {
mapEntry.getValue().updateLoan(this);
@@ -6411,13 +6417,10 @@ public class Loan extends
AbstractAuditableWithUTCDateTimeCustom {
final LoanRepaymentScheduleTransactionProcessor
loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
.determineProcessor(this.transactionProcessingStrategyCode);
- final Money overpaidAmount =
MathUtil.negativeToZero(calculateTotalOverpayment()); // Before Transaction
- if (chargebackTransaction.isNotZero(loanCurrency())) {
- addLoanTransaction(chargebackTransaction);
- }
-
loanRepaymentScheduleTransactionProcessor.handleChargeback(chargebackTransaction,
getCurrency(), overpaidAmount,
- getRepaymentScheduleInstallments());
+ addLoanTransaction(chargebackTransaction);
+
loanRepaymentScheduleTransactionProcessor.processLatestTransaction(chargebackTransaction,
getCurrency(),
+ getRepaymentScheduleInstallments(), getActiveCharges(),
getTotalOverpaidAsMoney());
updateLoanSummaryDerivedFields();
if
(!doPostLoanTransactionChecks(chargebackTransaction.getTransactionDate(),
loanLifecycleStateMachine)) {
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/LoanRepaymentScheduleTransactionProcessor.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/LoanRepaymentScheduleTransactionProcessor.java
index 52dd30b4b..9131646ea 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/LoanRepaymentScheduleTransactionProcessor.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/LoanRepaymentScheduleTransactionProcessor.java
@@ -36,15 +36,22 @@ public interface LoanRepaymentScheduleTransactionProcessor {
boolean accept(String s);
- void handleTransaction(LoanTransaction loanTransaction, MonetaryCurrency
currency, List<LoanRepaymentScheduleInstallment> installments,
- Set<LoanCharge> charges);
+ /**
+ * Provides support for processing the latest transaction (which should be
latest transaction) against the loan
+ * schedule.
+ */
+ void processLatestTransaction(LoanTransaction loanTransaction,
MonetaryCurrency currency,
+ List<LoanRepaymentScheduleInstallment> installments,
Set<LoanCharge> charges, Money overpaidAmount);
- ChangedTransactionDetail handleTransaction(LocalDate disbursementDate,
List<LoanTransaction> repaymentsOrWaivers,
+ /**
+ * Provides support for passing all {@link LoanTransaction}'s so it will
completely re-process the entire loan
+ * schedule. This is required in cases where the {@link LoanTransaction}
being processed is in the past and falls
+ * before existing transactions or and adjustment is made to an existing
in which case the entire loan schedule
+ * needs to be re-processed.
+ */
+ ChangedTransactionDetail reprocessLoanTranactions(LocalDate
disbursementDate, List<LoanTransaction> repaymentsOrWaivers,
MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment>
repaymentScheduleInstallments, Set<LoanCharge> charges);
- void handleWriteOff(LoanTransaction loanTransaction, MonetaryCurrency
loanCurrency,
- List<LoanRepaymentScheduleInstallment>
repaymentScheduleInstallments);
-
Money handleRepaymentSchedule(List<LoanTransaction>
transactionsPostDisbursement, MonetaryCurrency currency,
List<LoanRepaymentScheduleInstallment> installments,
Set<LoanCharge> loanCharges);
@@ -52,14 +59,4 @@ public interface LoanRepaymentScheduleTransactionProcessor {
* Used in interest recalculation to introduce new interest only
installment.
*/
boolean isInterestFirstRepaymentScheduleTransactionProcessor();
-
- void handleRefund(LoanTransaction loanTransaction, MonetaryCurrency
currency, List<LoanRepaymentScheduleInstallment> installments,
- Set<LoanCharge> charges);
-
- void handleChargeback(LoanTransaction loanTransaction, MonetaryCurrency
currency, Money overpaidAmount,
- List<LoanRepaymentScheduleInstallment> installments);
-
- void processTransactionsFromDerivedFields(List<LoanTransaction>
transactionsPostDisbursement, MonetaryCurrency currency,
- List<LoanRepaymentScheduleInstallment> installments,
Set<LoanCharge> charges);
-
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
index 3f448f738..7ac6dff24 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/AbstractLoanRepaymentScheduleTransactionProcessor.java
@@ -63,15 +63,8 @@ public abstract class
AbstractLoanRepaymentScheduleTransactionProcessor implemen
return getCode().equalsIgnoreCase(s) || getName().equalsIgnoreCase(s);
}
- /**
- * Provides support for passing all {@link LoanTransaction}'s so it will
completely re-process the entire loan
- * schedule. This is required in cases where the {@link LoanTransaction}
being processed is in the past and falls
- * before existing transactions or and adjustment is made to an existing
in which case the entire loan schedule
- * needs to be re-processed.
- */
-
@Override
- public ChangedTransactionDetail handleTransaction(final LocalDate
disbursementDate,
+ public ChangedTransactionDetail reprocessLoanTranactions(final LocalDate
disbursementDate,
final List<LoanTransaction> transactionsPostDisbursement, final
MonetaryCurrency currency,
final List<LoanRepaymentScheduleInstallment> installments, final
Set<LoanCharge> charges) {
@@ -155,20 +148,15 @@ public abstract class
AbstractLoanRepaymentScheduleTransactionProcessor implemen
for (final LoanTransaction loanTransaction :
transactionsToBeProcessed) {
// TODO: analyze and remove this
if
(!loanTransaction.getTypeOf().equals(LoanTransactionType.REFUND_FOR_ACTIVE_LOAN))
{
- final Comparator<LoanRepaymentScheduleInstallment> byDate =
new Comparator<LoanRepaymentScheduleInstallment>() {
-
- @Override
- public int compare(LoanRepaymentScheduleInstallment ord1,
LoanRepaymentScheduleInstallment ord2) {
- return ord1.getDueDate().compareTo(ord2.getDueDate());
- }
- };
- Collections.sort(installments, byDate);
+ final Comparator<LoanRepaymentScheduleInstallment> byDate =
Comparator
+
.comparing(LoanRepaymentScheduleInstallment::getDueDate);
+ installments.sort(byDate);
}
if (loanTransaction.isRepaymentLikeType() ||
loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
// pass through for new transactions
if (loanTransaction.getId() == null) {
- handleTransaction(loanTransaction, currency, installments,
charges);
+ processLatestTransaction(loanTransaction, currency,
installments, charges, null);
loanTransaction.adjustInterestComponent(currency);
} else {
/**
@@ -179,7 +167,7 @@ public abstract class
AbstractLoanRepaymentScheduleTransactionProcessor implemen
// Reset derived component of new loan transaction and
// re-process transaction
- handleTransaction(newLoanTransaction, currency,
installments, charges);
+ processLatestTransaction(newLoanTransaction, currency,
installments, charges, null);
newLoanTransaction.adjustInterestComponent(currency);
/**
* Check if the transaction amounts have changed. If so,
reverse the original transaction and update
@@ -212,6 +200,134 @@ public abstract class
AbstractLoanRepaymentScheduleTransactionProcessor implemen
return changedTransactionDetail;
}
+ @Override
+ public void processLatestTransaction(final LoanTransaction
loanTransaction, final MonetaryCurrency currency,
+ final List<LoanRepaymentScheduleInstallment> installments, final
Set<LoanCharge> charges, Money overpaidAmount) {
+ switch (loanTransaction.getTypeOf()) {
+ case WRITEOFF -> handleWriteOff(loanTransaction, currency,
installments);
+ case REFUND_FOR_ACTIVE_LOAN -> handleRefund(loanTransaction,
currency, installments, charges);
+ case CHARGEBACK -> handleChargeback(loanTransaction, currency,
overpaidAmount, installments);
+ default -> {
+ Money transactionAmountUnprocessed =
handleTransactionAndCharges(loanTransaction, currency, installments, charges,
null,
+ false);
+ if (transactionAmountUnprocessed.isGreaterThanZero()) {
+ if (loanTransaction.isWaiver()) {
+
loanTransaction.updateComponentsAndTotal(transactionAmountUnprocessed.zero(),
transactionAmountUnprocessed.zero(),
+ transactionAmountUnprocessed.zero(),
transactionAmountUnprocessed.zero());
+ } else {
+ onLoanOverpayment(loanTransaction,
transactionAmountUnprocessed);
+
loanTransaction.updateOverPayments(transactionAmountUnprocessed);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public Money handleRepaymentSchedule(final List<LoanTransaction>
transactionsPostDisbursement, final MonetaryCurrency currency,
+ final List<LoanRepaymentScheduleInstallment> installments,
Set<LoanCharge> loanCharges) {
+ Money unProcessed = Money.zero(currency);
+ for (final LoanTransaction loanTransaction :
transactionsPostDisbursement) {
+ if (loanTransaction.isRepaymentLikeType() ||
loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
+ loanTransaction.resetDerivedComponents();
+ }
+ if (loanTransaction.isInterestWaiver()) {
+ processTransaction(loanTransaction, currency, installments,
loanCharges, null);
+ } else {
+ unProcessed = processTransaction(loanTransaction, currency,
installments, loanCharges, null);
+ }
+ }
+ return unProcessed;
+ }
+
+ @Override
+ public boolean isInterestFirstRepaymentScheduleTransactionProcessor() {
+ return false;
+ }
+
+ // abstract interface
+
+ /**
+ * For early/'in advance' repayments.
+ *
+ * @param transactionMappings
+ * TODO
+ * @param charges
+ */
+ protected abstract Money
handleTransactionThatIsPaymentInAdvanceOfInstallment(LoanRepaymentScheduleInstallment
currentInstallment,
+ List<LoanRepaymentScheduleInstallment> installments,
LoanTransaction loanTransaction, Money paymentInAdvance,
+ List<LoanTransactionToRepaymentScheduleMapping>
transactionMappings, Set<LoanCharge> charges);
+
+ /**
+ * For normal on-time repayments.
+ *
+ * @param transactionMappings
+ * TODO
+ * @param charges
+ */
+ protected abstract Money
handleTransactionThatIsOnTimePaymentOfInstallment(LoanRepaymentScheduleInstallment
currentInstallment,
+ LoanTransaction loanTransaction, Money
transactionAmountUnprocessed,
+ List<LoanTransactionToRepaymentScheduleMapping>
transactionMappings, Set<LoanCharge> charges);
+
+ /**
+ * For late repayments, how should components of installment be paid off
+ *
+ * @param transactionMappings
+ * TODO
+ * @param charges
+ */
+ protected abstract Money
handleTransactionThatIsALateRepaymentOfInstallment(LoanRepaymentScheduleInstallment
currentInstallment,
+ List<LoanRepaymentScheduleInstallment> installments,
LoanTransaction loanTransaction, Money transactionAmountUnprocessed,
+ List<LoanTransactionToRepaymentScheduleMapping>
transactionMappings, Set<LoanCharge> charges);
+
+ /**
+ * Invoked when a transaction results in an over-payment of the full loan.
+ *
+ * transaction amount is greater than the total expected principal and
interest of the loan.
+ */
+ @SuppressWarnings("unused")
+ protected void onLoanOverpayment(final LoanTransaction loanTransaction,
final Money loanOverPaymentAmount) {
+ // empty implementation by default.
+ }
+
+ /**
+ * Invoked when a there is a refund of an active loan or undo of an active
loan
+ *
+ * Undoes principal, interest, fees and charges of this transaction based
on the repayment strategy
+ *
+ * @param transactionMappings
+ * TODO
+ *
+ */
+ protected abstract Money
handleRefundTransactionPaymentOfInstallment(LoanRepaymentScheduleInstallment
currentInstallment,
+ LoanTransaction loanTransaction, Money
transactionAmountUnprocessed,
+ List<LoanTransactionToRepaymentScheduleMapping>
transactionMappings);
+
+ /**
+ * This method is responsible for checking if the current transaction is
'an advance/early payment' based on the
+ * details passed through.
+ *
+ * Default implementation is check transaction date is before installment
due date.
+ */
+ protected boolean isTransactionInAdvanceOfInstallment(final int
installmentIndex,
+ final List<LoanRepaymentScheduleInstallment> installments, final
LocalDate transactionDate) {
+ final LoanRepaymentScheduleInstallment currentInstallment =
installments.get(installmentIndex);
+ return transactionDate.isBefore(currentInstallment.getDueDate());
+ }
+
+ /**
+ * This method is responsible for checking if the current transaction is
'an advance/early payment' based on the
+ * details passed through.
+ *
+ * Default implementation simply processes transactions as 'Late' if the
transaction date is after the installment
+ * due date.
+ */
+ protected boolean isTransactionALateRepaymentOnInstallment(final int
installmentIndex,
+ final List<LoanRepaymentScheduleInstallment> installments, final
LocalDate transactionDate) {
+ final LoanRepaymentScheduleInstallment currentInstallment =
installments.get(installmentIndex);
+ return transactionDate.isAfter(currentInstallment.getDueDate());
+ }
+
private void recalculateChargeOffTransaction(ChangedTransactionDetail
changedTransactionDetail, LoanTransaction loanTransaction,
MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment>
installments) {
final LoanTransaction newLoanTransaction =
LoanTransaction.copyTransactionProperties(loanTransaction);
@@ -422,42 +538,9 @@ public abstract class
AbstractLoanRepaymentScheduleTransactionProcessor implemen
}
}
- /**
- * Provides support for processing the latest transaction (which should be
latest transaction) against the loan
- * schedule.
- */
- @Override
- public void handleTransaction(final LoanTransaction loanTransaction, final
MonetaryCurrency currency,
- final List<LoanRepaymentScheduleInstallment> installments, final
Set<LoanCharge> charges) {
-
- final Money amountToProcess = null;
- final boolean isChargeAmount = false;
- handleTransaction(loanTransaction, currency, installments, charges,
amountToProcess, isChargeAmount);
-
- }
-
- private void handleTransaction(final LoanTransaction loanTransaction,
final MonetaryCurrency currency,
- final List<LoanRepaymentScheduleInstallment> installments, final
Set<LoanCharge> charges, final Money chargeAmountToProcess,
- final boolean isFeeCharge) {
-
- Money transactionAmountUnprocessed =
handleTransactionAndCharges(loanTransaction, currency, installments, charges,
- chargeAmountToProcess, isFeeCharge);
-
- if (transactionAmountUnprocessed.isGreaterThanZero()) {
- if (loanTransaction.isWaiver()) {
-
loanTransaction.updateComponentsAndTotal(transactionAmountUnprocessed.zero(),
transactionAmountUnprocessed.zero(),
- transactionAmountUnprocessed.zero(),
transactionAmountUnprocessed.zero());
- } else {
- onLoanOverpayment(loanTransaction,
transactionAmountUnprocessed);
-
loanTransaction.updateOverPayments(transactionAmountUnprocessed);
- }
- }
- }
-
private Money handleTransactionAndCharges(final LoanTransaction
loanTransaction, final MonetaryCurrency currency,
final List<LoanRepaymentScheduleInstallment> installments, final
Set<LoanCharge> charges, final Money chargeAmountToProcess,
final boolean isFeeCharge) {
- // to.
if (loanTransaction.isRepaymentLikeType() ||
loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
loanTransaction.resetDerivedComponents();
}
@@ -505,20 +588,13 @@ public abstract class
AbstractLoanRepaymentScheduleTransactionProcessor implemen
for (final LoanRepaymentScheduleInstallment currentInstallment :
installments) {
if (transactionAmountUnprocessed.isGreaterThanZero()) {
if (currentInstallment.isNotFullyPaidOff()) {
-
- // is this transaction early/late/on-time with respect to
- // the
- // current installment?
if (isTransactionInAdvanceOfInstallment(installmentIndex,
installments, transactionDate)) {
transactionAmountUnprocessed =
handleTransactionThatIsPaymentInAdvanceOfInstallment(currentInstallment,
installments, loanTransaction,
transactionAmountUnprocessed, transactionMappings, charges);
} else if
(isTransactionALateRepaymentOnInstallment(installmentIndex, installments,
transactionDate)) {
- // does this result in a late payment of existing
- // installment?
transactionAmountUnprocessed =
handleTransactionThatIsALateRepaymentOfInstallment(currentInstallment,
installments,
loanTransaction, transactionAmountUnprocessed,
transactionMappings, charges);
} else {
- // standard transaction
transactionAmountUnprocessed =
handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment,
loanTransaction, transactionAmountUnprocessed,
transactionMappings, charges);
}
@@ -611,8 +687,7 @@ public abstract class
AbstractLoanRepaymentScheduleTransactionProcessor implemen
return earliestUnpaidCharge;
}
- @Override
- public void handleWriteOff(final LoanTransaction loanTransaction, final
MonetaryCurrency currency,
+ private void handleWriteOff(final LoanTransaction loanTransaction, final
MonetaryCurrency currency,
final List<LoanRepaymentScheduleInstallment> installments) {
final LocalDate transactionDate = loanTransaction.getTransactionDate();
@@ -637,121 +712,16 @@ public abstract class
AbstractLoanRepaymentScheduleTransactionProcessor implemen
loanTransaction.updateComponentsAndTotal(principalPortion,
interestPortion, feeChargesPortion, penaltychargesPortion);
}
- // abstract interface
- /**
- * This method is responsible for checking if the current transaction is
'an advance/early payment' based on the
- * details passed through.
- *
- * Default implementation simply processes transactions as 'Late' if the
transaction date is after the installment
- * due date.
- */
- protected boolean isTransactionALateRepaymentOnInstallment(final int
installmentIndex,
- final List<LoanRepaymentScheduleInstallment> installments, final
LocalDate transactionDate) {
-
- final LoanRepaymentScheduleInstallment currentInstallment =
installments.get(installmentIndex);
-
- return transactionDate.isAfter(currentInstallment.getDueDate());
- }
-
- /**
- * For late repayments, how should components of installment be paid off
- *
- * @param transactionMappings
- * TODO
- * @param charges
- */
- protected abstract Money
handleTransactionThatIsALateRepaymentOfInstallment(LoanRepaymentScheduleInstallment
currentInstallment,
- List<LoanRepaymentScheduleInstallment> installments,
LoanTransaction loanTransaction, Money transactionAmountUnprocessed,
- List<LoanTransactionToRepaymentScheduleMapping>
transactionMappings, Set<LoanCharge> charges);
-
- /**
- * This method is responsible for checking if the current transaction is
'an advance/early payment' based on the
- * details passed through.
- *
- * Default implementation is check transaction date is before installment
due date.
- */
- protected boolean isTransactionInAdvanceOfInstallment(final int
currentInstallmentIndex,
- final List<LoanRepaymentScheduleInstallment> installments, final
LocalDate transactionDate) {
-
- final LoanRepaymentScheduleInstallment currentInstallment =
installments.get(currentInstallmentIndex);
-
- return transactionDate.isBefore(currentInstallment.getDueDate());
- }
-
- /**
- * For early/'in advance' repayments.
- *
- * @param transactionMappings
- * TODO
- * @param charges
- */
- protected abstract Money
handleTransactionThatIsPaymentInAdvanceOfInstallment(LoanRepaymentScheduleInstallment
currentInstallment,
- List<LoanRepaymentScheduleInstallment> installments,
LoanTransaction loanTransaction, Money paymentInAdvance,
- List<LoanTransactionToRepaymentScheduleMapping>
transactionMappings, Set<LoanCharge> charges);
-
- /**
- * For normal on-time repayments.
- *
- * @param transactionMappings
- * TODO
- * @param charges
- */
- protected abstract Money
handleTransactionThatIsOnTimePaymentOfInstallment(LoanRepaymentScheduleInstallment
currentInstallment,
- LoanTransaction loanTransaction, Money
transactionAmountUnprocessed,
- List<LoanTransactionToRepaymentScheduleMapping>
transactionMappings, Set<LoanCharge> charges);
-
- /**
- * Invoked when a transaction results in an over-payment of the full loan.
- *
- * transaction amount is greater than the total expected principal and
interest of the loan.
- */
- @SuppressWarnings("unused")
- protected void onLoanOverpayment(final LoanTransaction loanTransaction,
final Money loanOverPaymentAmount) {
- // empty implementation by default.
- }
-
- @Override
- public Money handleRepaymentSchedule(final List<LoanTransaction>
transactionsPostDisbursement, final MonetaryCurrency currency,
- final List<LoanRepaymentScheduleInstallment> installments,
Set<LoanCharge> loanCharges) {
- Money unProcessed = Money.zero(currency);
- for (final LoanTransaction loanTransaction :
transactionsPostDisbursement) {
- Money amountToProcess = null;
- if (loanTransaction.isRepaymentLikeType() ||
loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
- loanTransaction.resetDerivedComponents();
- }
- if (loanTransaction.isInterestWaiver()) {
- processTransaction(loanTransaction, currency, installments,
loanCharges, amountToProcess);
- } else {
- unProcessed = processTransaction(loanTransaction, currency,
installments, loanCharges, amountToProcess);
- }
- }
- return unProcessed;
- }
-
- @Override
- public boolean isInterestFirstRepaymentScheduleTransactionProcessor() {
- return false;
- }
-
- @Override
- public void handleChargeback(LoanTransaction loanTransaction,
MonetaryCurrency currency, Money overpaidAmount,
+ private void handleChargeback(LoanTransaction loanTransaction,
MonetaryCurrency currency, Money overpaidAmount,
List<LoanRepaymentScheduleInstallment> installments) {
processCreditTransaction(loanTransaction, overpaidAmount, currency,
installments);
}
- @Override
- public void handleRefund(LoanTransaction loanTransaction, MonetaryCurrency
currency,
+ private void handleRefund(LoanTransaction loanTransaction,
MonetaryCurrency currency,
List<LoanRepaymentScheduleInstallment> installments, final
Set<LoanCharge> charges) {
- // TODO Auto-generated method stub
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings =
new ArrayList<>();
- final Comparator<LoanRepaymentScheduleInstallment> byDate = new
Comparator<LoanRepaymentScheduleInstallment>() {
-
- @Override
- public int compare(LoanRepaymentScheduleInstallment ord1,
LoanRepaymentScheduleInstallment ord2) {
- return ord1.getDueDate().compareTo(ord2.getDueDate());
- }
- };
- Collections.sort(installments, Collections.reverseOrder(byDate));
+ final Comparator<LoanRepaymentScheduleInstallment> byDate =
Comparator.comparing(LoanRepaymentScheduleInstallment::getDueDate);
+ installments.sort(Collections.reverseOrder(byDate));
Money transactionAmountUnprocessed =
loanTransaction.getAmount(currency);
for (final LoanRepaymentScheduleInstallment currentInstallment :
installments) {
@@ -786,19 +756,6 @@ public abstract class
AbstractLoanRepaymentScheduleTransactionProcessor implemen
loanTransaction.updateLoanTransactionToRepaymentScheduleMappings(transactionMappings);
}
- /**
- * Invoked when a there is a refund of an active loan or undo of an active
loan
- *
- * Undoes principal, interest, fees and charges of this transaction based
on the repayment strategy
- *
- * @param transactionMappings
- * TODO
- *
- */
- protected abstract Money
handleRefundTransactionPaymentOfInstallment(LoanRepaymentScheduleInstallment
currentInstallment,
- LoanTransaction loanTransaction, Money
transactionAmountUnprocessed,
- List<LoanTransactionToRepaymentScheduleMapping>
transactionMappings);
-
private void undoChargesPaidAmountBy(final LoanTransaction
loanTransaction, final Money feeCharges, final Set<LoanCharge> charges,
final Integer installmentNumber) {
@@ -853,91 +810,4 @@ public abstract class
AbstractLoanRepaymentScheduleTransactionProcessor implemen
return latestPaidCharge;
}
-
- @Override
- public void processTransactionsFromDerivedFields(List<LoanTransaction>
transactionsPostDisbursement, MonetaryCurrency currency,
- List<LoanRepaymentScheduleInstallment> installments, final
Set<LoanCharge> charges) {
- for (final LoanTransaction loanTransaction :
transactionsPostDisbursement) {
- if (!loanTransaction.isAccrualTransaction()) {
- processTransactionFromDerivedFields(loanTransaction, currency,
installments, charges);
- }
- }
- }
-
- private void processTransactionFromDerivedFields(final LoanTransaction
loanTransaction, MonetaryCurrency currency,
- List<LoanRepaymentScheduleInstallment> installments, final
Set<LoanCharge> charges) {
- Money principal = loanTransaction.getPrincipalPortion(currency);
- Money interest = loanTransaction.getInterestPortion(currency);
- if (loanTransaction.isInterestWaiver()) {
- interest = loanTransaction.getAmount(currency);
- }
- Money feeCharges = loanTransaction.getFeeChargesPortion(currency);
- Money penaltyCharges =
loanTransaction.getPenaltyChargesPortion(currency);
- final LocalDate transactionDate = loanTransaction.getTransactionDate();
- if (principal.isGreaterThanZero() || interest.isGreaterThanZero() ||
feeCharges.isGreaterThanZero()
- || penaltyCharges.isGreaterThanZero()) {
- for (final LoanRepaymentScheduleInstallment currentInstallment :
installments) {
- if (currentInstallment.isNotFullyPaidOff()) {
- if (penaltyCharges.isGreaterThanZero()) {
- Money penaltyChargesPortion = Money.zero(currency);
- if (loanTransaction.isWaiver()) {
- penaltyChargesPortion =
currentInstallment.waivePenaltyChargesComponent(transactionDate,
penaltyCharges);
- } else {
- penaltyChargesPortion =
currentInstallment.payPenaltyChargesComponent(transactionDate, penaltyCharges);
- }
- penaltyCharges =
penaltyCharges.minus(penaltyChargesPortion);
- }
-
- if (feeCharges.isGreaterThanZero()) {
- Money feeChargesPortion = Money.zero(currency);
- if (loanTransaction.isWaiver()) {
- feeChargesPortion =
currentInstallment.waiveFeeChargesComponent(transactionDate, feeCharges);
- } else {
- feeChargesPortion =
currentInstallment.payFeeChargesComponent(transactionDate, feeCharges);
- }
- feeCharges = feeCharges.minus(feeChargesPortion);
- }
-
- if (interest.isGreaterThanZero()) {
- Money interestPortion = Money.zero(currency);
- if (loanTransaction.isWaiver()) {
- interestPortion =
currentInstallment.waiveInterestComponent(transactionDate, interest);
- } else {
- interestPortion =
currentInstallment.payInterestComponent(transactionDate, interest);
- }
- interest = interest.minus(interestPortion);
- }
-
- if (principal.isGreaterThanZero()) {
- Money principalPortion =
currentInstallment.payPrincipalComponent(transactionDate, principal);
- principal = principal.minus(principalPortion);
- }
- }
- if (!(principal.isGreaterThanZero() ||
interest.isGreaterThanZero() || feeCharges.isGreaterThanZero()
- || penaltyCharges.isGreaterThanZero())) {
- break;
- }
- }
- }
-
- final Set<LoanCharge> loanFees = extractFeeCharges(charges);
- final Set<LoanCharge> loanPenalties = extractPenaltyCharges(charges);
- Integer installmentNumber = null;
- if (loanTransaction.isChargePayment() && installments.size() == 1) {
- installmentNumber = installments.get(0).getInstallmentNumber();
- }
-
- if (loanTransaction.isNotWaiver()) {
- feeCharges = loanTransaction.getFeeChargesPortion(currency);
- penaltyCharges =
loanTransaction.getPenaltyChargesPortion(currency);
- if (feeCharges.isGreaterThanZero()) {
- updateChargesPaidAmountBy(loanTransaction, feeCharges,
loanFees, installmentNumber);
- }
-
- if (penaltyCharges.isGreaterThanZero()) {
- updateChargesPaidAmountBy(loanTransaction, penaltyCharges,
loanPenalties, installmentNumber);
- }
- }
- }
-
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
index 5fc2bc35c..aa236efde 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
@@ -18,10 +18,13 @@
*/
package
org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl;
+import java.time.LocalDate;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.NotImplementedException;
+import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
+import
org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail;
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
@@ -69,4 +72,22 @@ public class AdvancedPaymentScheduleTransactionProcessor
extends AbstractLoanRep
List<LoanTransactionToRepaymentScheduleMapping>
transactionMappings) {
throw new NotImplementedException();
}
+
+ @Override
+ public ChangedTransactionDetail reprocessLoanTranactions(LocalDate
disbursementDate, List<LoanTransaction> transactionsPostDisbursement,
+ MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment>
installments, Set<LoanCharge> charges) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void processLatestTransaction(LoanTransaction loanTransaction,
MonetaryCurrency currency,
+ List<LoanRepaymentScheduleInstallment> installments,
Set<LoanCharge> charges, Money overpaidAmount) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public Money handleRepaymentSchedule(List<LoanTransaction>
transactionsPostDisbursement, MonetaryCurrency currency,
+ List<LoanRepaymentScheduleInstallment> installments,
Set<LoanCharge> loanCharges) {
+ return super.handleRepaymentSchedule(transactionsPostDisbursement,
currency, installments, loanCharges);
+ }
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/CreocoreLoanRepaymentScheduleTransactionProcessor.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/CreocoreLoanRepaymentScheduleTransactionProcessor.java
index 88719e6f5..501f93558 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/CreocoreLoanRepaymentScheduleTransactionProcessor.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/CreocoreLoanRepaymentScheduleTransactionProcessor.java
@@ -56,18 +56,6 @@ public class
CreocoreLoanRepaymentScheduleTransactionProcessor extends AbstractL
return STRATEGY_NAME;
}
- /**
- * For creocore, early is defined as any date before the installment due
date
- */
- @Override
- protected boolean isTransactionInAdvanceOfInstallment(final int
currentInstallmentIndex,
- final List<LoanRepaymentScheduleInstallment> installments, final
LocalDate transactionDate) {
-
- final LoanRepaymentScheduleInstallment currentInstallment =
installments.get(currentInstallmentIndex);
-
- return transactionDate.isBefore(currentInstallment.getDueDate());
- }
-
/**
* For early/'in advance' repayments, pay off in the same way as on-time
payments, interest first then principal.
*/
@@ -153,12 +141,6 @@ public class
CreocoreLoanRepaymentScheduleTransactionProcessor extends AbstractL
return transactionAmountRemaining;
}
- @SuppressWarnings("unused")
- @Override
- protected void onLoanOverpayment(final LoanTransaction loanTransaction,
final Money loanOverPaymentAmount) {
- // dont do anything for with loan over-payment
- }
-
@Override
protected Money handleRefundTransactionPaymentOfInstallment(final
LoanRepaymentScheduleInstallment currentInstallment,
final LoanTransaction loanTransaction, final Money
transactionAmountUnprocessed,
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor.java
index f9e038652..7916e894d 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor.java
@@ -245,11 +245,6 @@ public class
DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactio
return transactionAmountRemaining;
}
- @Override
- protected void onLoanOverpayment(final LoanTransaction loanTransaction,
final Money loanOverPaymentAmount) {
- // TODO - KW - dont do anything with loan over-payment for now
- }
-
@Override
protected Money handleRefundTransactionPaymentOfInstallment(final
LoanRepaymentScheduleInstallment currentInstallment,
final LoanTransaction loanTransaction, final Money
transactionAmountUnprocessed,
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor.java
index 6a8bf1e6a..a16e7f15f 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor.java
@@ -247,11 +247,6 @@ public class
DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactio
return transactionAmountRemaining;
}
- @Override
- protected void onLoanOverpayment(final LoanTransaction loanTransaction,
final Money loanOverPaymentAmount) {
- // TODO - KW - dont do anything with loan over-payment for now
- }
-
@Override
protected Money handleRefundTransactionPaymentOfInstallment(final
LoanRepaymentScheduleInstallment currentInstallment,
final LoanTransaction loanTransaction, final Money
transactionAmountUnprocessed,
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/FineractStyleLoanRepaymentScheduleTransactionProcessor.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/FineractStyleLoanRepaymentScheduleTransactionProcessor.java
index 11d73813b..fb3ab2f02 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/FineractStyleLoanRepaymentScheduleTransactionProcessor.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/FineractStyleLoanRepaymentScheduleTransactionProcessor.java
@@ -56,15 +56,6 @@ public class
FineractStyleLoanRepaymentScheduleTransactionProcessor extends Abst
return STRATEGY_NAME;
}
- @Override
- protected boolean isTransactionInAdvanceOfInstallment(final int
currentInstallmentIndex,
- final List<LoanRepaymentScheduleInstallment> installments, final
LocalDate transactionDate) {
-
- final LoanRepaymentScheduleInstallment currentInstallment =
installments.get(currentInstallmentIndex);
-
- return transactionDate.isBefore(currentInstallment.getDueDate());
- }
-
/**
* For early/'in advance' repayments, pay off in the same way as on-time
payments, interest first then principal.
*/
@@ -151,11 +142,6 @@ public class
FineractStyleLoanRepaymentScheduleTransactionProcessor extends Abst
return transactionAmountRemaining;
}
- @Override
- protected void onLoanOverpayment(final LoanTransaction loanTransaction,
final Money loanOverPaymentAmount) {
- // TODO - KW - dont do anything with loan over-payment for now
- }
-
@Override
protected Money handleRefundTransactionPaymentOfInstallment(final
LoanRepaymentScheduleInstallment currentInstallment,
final LoanTransaction loanTransaction, final Money
transactionAmountUnprocessed,
@@ -164,10 +150,10 @@ public class
FineractStyleLoanRepaymentScheduleTransactionProcessor extends Abst
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());
+ Money principalPortion = Money.zero(currency);
+ Money interestPortion = Money.zero(currency);
+ Money feeChargesPortion = Money.zero(currency);
+ Money penaltyChargesPortion = Money.zero(currency);
principalPortion =
currentInstallment.unpayPrincipalComponent(transactionDate,
transactionAmountRemaining);
transactionAmountRemaining =
transactionAmountRemaining.minus(principalPortion);
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java
index 3e327c5cd..e94cee83a 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java
@@ -216,9 +216,6 @@ public class
HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
return transactionAmountRemaining;
}
- @Override
- protected void onLoanOverpayment(final LoanTransaction loanTransaction,
final Money loanOverPaymentAmount) {}
-
@Override
protected Money handleRefundTransactionPaymentOfInstallment(final
LoanRepaymentScheduleInstallment currentInstallment,
final LoanTransaction loanTransaction, final Money
transactionAmountUnprocessed,
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/RBILoanRepaymentScheduleTransactionProcessor.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/RBILoanRepaymentScheduleTransactionProcessor.java
index 97de4da3b..9987180b9 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/RBILoanRepaymentScheduleTransactionProcessor.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/RBILoanRepaymentScheduleTransactionProcessor.java
@@ -59,19 +59,6 @@ public class RBILoanRepaymentScheduleTransactionProcessor
extends AbstractLoanRe
return STRATEGY_NAME;
}
- /**
- * For creocore, early is defined as any date before the installment due
date
- */
- @SuppressWarnings("unused")
- @Override
- protected boolean isTransactionInAdvanceOfInstallment(final int
currentInstallmentIndex,
- final List<LoanRepaymentScheduleInstallment> installments, final
LocalDate transactionDate) {
-
- final LoanRepaymentScheduleInstallment currentInstallment =
installments.get(currentInstallmentIndex);
-
- return transactionDate.isBefore(currentInstallment.getDueDate());
- }
-
/**
* For early/'in advance' repayments, pays off principal component only.
*/
@@ -259,12 +246,6 @@ public class RBILoanRepaymentScheduleTransactionProcessor
extends AbstractLoanRe
return transactionAmountRemaining;
}
- @SuppressWarnings("unused")
- @Override
- protected void onLoanOverpayment(final LoanTransaction loanTransaction,
final Money loanOverPaymentAmount) {
- // dont do anything for with loan over-payment
- }
-
@Override
public boolean isInterestFirstRepaymentScheduleTransactionProcessor() {
return true;
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
index d76f75e3f..8229dbddd 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
@@ -2808,8 +2808,8 @@ public abstract class AbstractLoanScheduleGenerator
implements LoanScheduleGener
loanRepaymentScheduleTransactionProcessor, onDate,
calculateTill);
List<LoanTransaction> loanTransactions =
loan.retrieveListOfTransactionsPostDisbursementExcludeAccruals();
-
loanRepaymentScheduleTransactionProcessor.handleTransaction(loanApplicationTerms.getExpectedDisbursementDate(),
loanTransactions,
- currency, loanScheduleDTO.getInstallments(),
loan.getActiveCharges());
+
loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(loanApplicationTerms.getExpectedDisbursementDate(),
+ loanTransactions, currency, loanScheduleDTO.getInstallments(),
loan.getActiveCharges());
Money feeCharges = Money.zero(currency);
Money penaltyCharges = Money.zero(currency);
Money totalPrincipal = Money.zero(currency);
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java
index 342ca5583..83b4c0508 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java
@@ -809,8 +809,8 @@ public class LoanChargeWritePlatformServiceImpl implements
LoanChargeWritePlatfo
defaultLoanLifecycleStateMachine.transition(LoanEvent.LOAN_REPAYMENT_OR_WAIVER,
loan);
final LoanRepaymentScheduleTransactionProcessor
loanRepaymentScheduleTransactionProcessor =
loanRepaymentScheduleTransactionProcessorFactory
.determineProcessor(loan.transactionProcessingStrategy());
-
loanRepaymentScheduleTransactionProcessor.handleTransaction(loanChargeAdjustmentTransaction,
loan.getCurrency(),
- loan.getRepaymentScheduleInstallments(),
loan.getActiveCharges());
+
loanRepaymentScheduleTransactionProcessor.processLatestTransaction(loanChargeAdjustmentTransaction,
loan.getCurrency(),
+ loan.getRepaymentScheduleInstallments(),
loan.getActiveCharges(), loan.getTotalOverpaidAsMoney());
loan.addLoanTransaction(loanChargeAdjustmentTransaction);
loan.updateLoanSummaryAndStatus();