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 4c503fff0 FINERACT-2060: Fix balance of reamortization at the event of
reverse-replay
4c503fff0 is described below
commit 4c503fff0de67dc45e0fe2d1b1d3ac435a879683
Author: Adam Saghy <[email protected]>
AuthorDate: Fri Apr 5 19:23:51 2024 +0200
FINERACT-2060: Fix balance of reamortization at the event of reverse-replay
---
.../resources/features/LoanReAmortization.feature | 2 +-
...dvancedPaymentScheduleTransactionProcessor.java | 15 +-
.../common/loans/LoanTestLifecycleExtension.java | 2 +-
.../LoanReAmortizationIntegrationTest.java | 435 ++++++++++++++-------
4 files changed, 291 insertions(+), 163 deletions(-)
diff --git
a/fineract-e2e-tests-runner/src/test/resources/features/LoanReAmortization.feature
b/fineract-e2e-tests-runner/src/test/resources/features/LoanReAmortization.feature
index 2f2c50191..c0bb30b4e 100644
---
a/fineract-e2e-tests-runner/src/test/resources/features/LoanReAmortization.feature
+++
b/fineract-e2e-tests-runner/src/test/resources/features/LoanReAmortization.feature
@@ -250,7 +250,7 @@ Feature: LoanReAmortization
| 01 January 2024 | Disbursement | 500.0 | 0.0 | 0.0 |
0.0 | 0.0 | 500.0 |
| 01 January 2024 | Down Payment | 125.0 | 125.0 | 0.0 |
0.0 | 0.0 | 375.0 |
| 15 January 2024 | Repayment | 125.0 | 125.0 | 0.0 |
0.0 | 0.0 | 250.0 |
- | 01 February 2024 | Re-amortize | 375.0 | 375.0 | 0.0 |
0.0 | 0.0 | 0.0 |
+ | 01 February 2024 | Re-amortize | 125.0 | 125.0 | 0.0 |
0.0 | 0.0 | 0.0 |
@TestRailId:C3076 @AdvancedPaymentAllocation
Scenario: Verify Loan re-amortization transaction - UC4: N+1 Installment
scenario
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
index 37b920325..e1f12c30d 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java
@@ -206,7 +206,6 @@ public class AdvancedPaymentScheduleTransactionProcessor
extends AbstractLoanRep
private void handleReAmortization(LoanTransaction loanTransaction,
MonetaryCurrency currency,
List<LoanRepaymentScheduleInstallment> installments) {
- BigDecimal remainingAmount = loanTransaction.getAmount();
LocalDate transactionDate = loanTransaction.getTransactionDate();
List<LoanRepaymentScheduleInstallment> previousInstallments =
installments.stream() //
.filter(installment ->
!installment.getDueDate().isAfter(transactionDate)) //
@@ -224,28 +223,26 @@ public class AdvancedPaymentScheduleTransactionProcessor
extends AbstractLoanRep
installment.updateDerivedFields(currency, transactionDate);
}
- if (overallOverDuePrincipal.compareTo(remainingAmount) != 0) {
- remainingAmount = overallOverDuePrincipal;
- loanTransaction.updateComponentsAndTotal(Money.of(currency,
remainingAmount), Money.zero(currency), Money.zero(currency),
- Money.zero(currency));
- }
+ loanTransaction.resetDerivedComponents();
+ loanTransaction.updateComponentsAndTotal(Money.of(currency,
overallOverDuePrincipal), Money.zero(currency), Money.zero(currency),
+ Money.zero(currency));
LoanRepaymentScheduleInstallment lastFutureInstallment =
futureInstallments.stream()
.max(Comparator.comparing(LoanRepaymentScheduleInstallment::getDueDate)).get();
- BigDecimal reAmortizationAmountPerInstallment =
remainingAmount.divide(BigDecimal.valueOf(futureInstallments.size()),
+ BigDecimal reAmortizationAmountPerInstallment =
overallOverDuePrincipal.divide(BigDecimal.valueOf(futureInstallments.size()),
MoneyHelper.getRoundingMode());
Integer installmentAmountInMultiplesOf =
loanTransaction.getLoan().getLoanProduct().getInstallmentAmountInMultiplesOf();
for (LoanRepaymentScheduleInstallment installment :
futureInstallments) {
if (lastFutureInstallment.equals(installment)) {
- installment.addToPrincipal(transactionDate, Money.of(currency,
remainingAmount));
+ installment.addToPrincipal(transactionDate, Money.of(currency,
overallOverDuePrincipal));
} else {
if (installmentAmountInMultiplesOf != null) {
reAmortizationAmountPerInstallment =
Money.roundToMultiplesOf(reAmortizationAmountPerInstallment,
installmentAmountInMultiplesOf);
}
installment.addToPrincipal(transactionDate, Money.of(currency,
reAmortizationAmountPerInstallment));
- remainingAmount =
remainingAmount.subtract(reAmortizationAmountPerInstallment);
+ overallOverDuePrincipal =
overallOverDuePrincipal.subtract(reAmortizationAmountPerInstallment);
}
}
}
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTestLifecycleExtension.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTestLifecycleExtension.java
index ffe553ad6..e3d9b0f16 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTestLifecycleExtension.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTestLifecycleExtension.java
@@ -43,7 +43,7 @@ public class LoanTestLifecycleExtension implements
AfterEachCallback {
private DateTimeFormatter dateFormatter = new
DateTimeFormatterBuilder().appendPattern("dd MMMM yyyy").toFormatter();
@Override
- public void afterEach(ExtensionContext context) throws Exception {
+ public void afterEach(ExtensionContext context) {
this.requestSpec = new
RequestSpecBuilder().setContentType(ContentType.JSON).build();
this.requestSpec.header("Authorization", "Basic " +
Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
this.responseSpec = new
ResponseSpecBuilder().expectStatusCode(200).build();
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/reamortization/LoanReAmortizationIntegrationTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/reamortization/LoanReAmortizationIntegrationTest.java
index eae605740..bb5d7a877 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/reamortization/LoanReAmortizationIntegrationTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/loan/reamortization/LoanReAmortizationIntegrationTest.java
@@ -25,7 +25,6 @@ import java.util.concurrent.atomic.AtomicLong;
import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
import org.apache.fineract.client.models.PostLoanProductsRequest;
import org.apache.fineract.client.models.PostLoanProductsResponse;
-import org.apache.fineract.client.models.PostLoansLoanIdResponse;
import org.apache.fineract.client.models.PostLoansRequest;
import org.apache.fineract.client.models.PostLoansResponse;
import org.apache.fineract.integrationtests.BaseLoanIntegrationTest;
@@ -41,11 +40,10 @@ import org.junit.jupiter.api.extension.ExtendWith;
public class LoanReAmortizationIntegrationTest extends BaseLoanIntegrationTest
{
public static final BigDecimal DOWN_PAYMENT_PERCENTAGE = new
BigDecimal(25);
+ private final AtomicLong loanId = new AtomicLong();
@Test
public void test_LoanReAmortizeTransaction_Works() {
- AtomicLong createdLoanId = new AtomicLong();
-
runAt("01 January 2023", () -> {
// Create Client
Long clientId =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
@@ -73,43 +71,37 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
.loanTermFrequencyType(RepaymentFrequencyType.MONTHS);
PostLoansResponse postLoansResponse =
loanTransactionHelper.applyLoan(applicationRequest);
+ loanId.set(postLoansResponse.getLoanId());
- PostLoansLoanIdResponse approvedLoanResult =
loanTransactionHelper.approveLoan(postLoansResponse.getResourceId(),
- approveLoanRequest(amount, "01 January 2023"));
-
- Long loanId = approvedLoanResult.getLoanId();
+
loanTransactionHelper.approveLoan(postLoansResponse.getResourceId(),
approveLoanRequest(amount, "01 January 2023"));
// disburse Loan
- disburseLoan(loanId, BigDecimal.valueOf(1250.0), "01 January
2023");
+ disburseLoan(loanId.get(), BigDecimal.valueOf(1250.0), "01 January
2023");
// verify transactions
- verifyTransactions(loanId, //
+ verifyTransactions(loanId.get(), //
transaction(1250.0, "Disbursement", "01 January 2023") //
);
// verify schedule
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(625.0, false, "01 February 2023"), //
installment(625.0, false, "01 March 2023") //
);
-
- createdLoanId.set(loanId);
});
runAt("02 February 2023", () -> {
- long loanId = createdLoanId.get();
-
// create re-amortize transaction
- reAmortizeLoan(loanId);
+ reAmortizeLoan(loanId.get());
// verify transactions
- verifyTransactions(loanId, //
+ verifyTransactions(loanId.get(), //
transaction(1250.0, "Disbursement", "01 January 2023"), //
transaction(625.0, "Re-amortize", "02 February 2023") //
);
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(0.0, true, "01 February 2023"), //
installment(1250.0, false, "01 March 2023") //
@@ -119,8 +111,6 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
@Test
public void test_LoanUndoReAmortizeTransaction_Works() {
- AtomicLong createdLoanId = new AtomicLong();
-
runAt("01 January 2023", () -> {
// Create Client
Long clientId =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
@@ -148,56 +138,48 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
.loanTermFrequencyType(RepaymentFrequencyType.MONTHS);
PostLoansResponse postLoansResponse =
loanTransactionHelper.applyLoan(applicationRequest);
+ loanId.set(postLoansResponse.getLoanId());
- PostLoansLoanIdResponse approvedLoanResult =
loanTransactionHelper.approveLoan(postLoansResponse.getResourceId(),
- approveLoanRequest(amount, "01 January 2023"));
-
- Long loanId = approvedLoanResult.getLoanId();
+
loanTransactionHelper.approveLoan(postLoansResponse.getResourceId(),
approveLoanRequest(amount, "01 January 2023"));
// disburse Loan
- disburseLoan(loanId, BigDecimal.valueOf(1250.0), "01 January
2023");
+ disburseLoan(loanId.get(), BigDecimal.valueOf(1250.0), "01 January
2023");
// verify transactions
- verifyTransactions(loanId, //
+ verifyTransactions(loanId.get(), //
transaction(1250.0, "Disbursement", "01 January 2023") //
);
// verify schedule
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(625.0, false, "01 February 2023"), //
installment(625.0, false, "01 March 2023") //
);
-
- createdLoanId.set(loanId);
});
runAt("02 February 2023", () -> {
- long loanId = createdLoanId.get();
-
// create re-amortize transaction
- reAmortizeLoan(loanId);
+ reAmortizeLoan(loanId.get());
// verify transactions
- verifyTransactions(loanId, //
+ verifyTransactions(loanId.get(), //
transaction(1250.0, "Disbursement", "01 January 2023"), //
transaction(625.0, "Re-amortize", "02 February 2023") //
);
});
runAt("03 February 2023", () -> {
- long loanId = createdLoanId.get();
-
// undo re-amortize transaction
- undoReAmortizeLoan(loanId);
+ undoReAmortizeLoan(loanId.get());
// verify transactions
- verifyTransactions(loanId, //
+ verifyTransactions(loanId.get(), //
transaction(1250.0, "Disbursement", "01 January 2023"), //
reversedTransaction(625.0, "Re-amortize", "02 February
2023") //
);
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(625.0, false, "01 February 2023"), //
installment(625.0, false, "01 March 2023") //
@@ -211,17 +193,17 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
Long clientId =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
Long loanProductId =
createLoanProductWithMultiDisbursalAndRepaymentsWithEnableDownPayment(3, 15);
- Long loanId = applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 500.0, 3, req -> {
+ loanId.set(applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 500.0, 3, req -> {
req.setRepaymentEvery(15);
req.setLoanTermFrequency(45);
req.setTransactionProcessingStrategyCode("advanced-payment-allocation-strategy");
req.setLoanScheduleProcessingType(LoanScheduleType.PROGRESSIVE.toString());
req.setLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL.toString());
- });
+ }));
- disburseLoan(loanId, BigDecimal.valueOf(500.00), "01 January
2023");
+ disburseLoan(loanId.get(), BigDecimal.valueOf(500.00), "01 January
2023");
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(125.0, false, "16 January 2023"), //
@@ -230,27 +212,33 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
);
updateBusinessDate("05 January 2023");
- addCharge(loanId, false, 10.0, "05 January 2023");
+ addCharge(loanId.get(), false, 10.0, "05 January 2023");
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(125.0, 0.0, 10.0, 135.0, false, "16 January
2023"), //
installment(125.0, false, "31 January 2023"), //
installment(125.0, false, "15 February 2023")//
);
+ });
+ runAt("25 January 2023", () -> {
+ reAmortizeLoan(loanId.get());
- updateBusinessDate("25 January 2023");
-
- reAmortizeLoan(loanId);
-
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(0.0, 0.0, 10.0, 10.0, false, "16 January
2023"), //
installment(187.5, false, "31 January 2023"), //
installment(187.5, false, "15 February 2023")//
);
+
+ // verify transactions
+ verifyTransactions(loanId.get(), //
+ transaction(500.0, "Disbursement", "01 January 2023"), //
+ transaction(125.0, "Down Payment", "01 January 2023"), //
+ transaction(125.0, "Re-amortize", "25 January 2023") //
+ );
});
}
@@ -260,35 +248,42 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
Long clientId =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
Long loanProductId =
createLoanProductWithMultiDisbursalAndRepaymentsWithEnableDownPayment(3, 15);
- Long loanId = applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 500.0, 3, req -> {
+ loanId.set(applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 500.0, 3, req -> {
req.setRepaymentEvery(15);
req.setLoanTermFrequency(45);
req.setTransactionProcessingStrategyCode("advanced-payment-allocation-strategy");
req.setLoanScheduleProcessingType(LoanScheduleType.PROGRESSIVE.toString());
req.setLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL.toString());
- });
+ }));
- disburseLoan(loanId, BigDecimal.valueOf(500.00), "01 January
2023");
+ disburseLoan(loanId.get(), BigDecimal.valueOf(500.00), "01 January
2023");
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(125.0, false, "16 January 2023"), //
installment(125.0, false, "31 January 2023"), //
installment(125.0, false, "15 February 2023")//
);
+ });
+ runAt("01 February 2023", () -> {
- updateBusinessDate("01 February 2023");
-
- reAmortizeLoan(loanId);
+ reAmortizeLoan(loanId.get());
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(0.0, true, "16 January 2023"), //
installment(0.0, true, "31 January 2023"), //
installment(375.0, false, "15 February 2023")//
);
+
+ // verify transactions
+ verifyTransactions(loanId.get(), //
+ transaction(500.0, "Disbursement", "01 January 2023"), //
+ transaction(125.0, "Down Payment", "01 January 2023"), //
+ transaction(250.0, "Re-amortize", "01 February 2023") //
+ );
});
}
@@ -298,38 +293,52 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
Long clientId =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
Long loanProductId =
createLoanProductWithMultiDisbursalAndRepaymentsWithEnableDownPayment(3, 15);
- Long loanId = applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 500.0, 3, req -> {
+ loanId.set(applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 500.0, 3, req -> {
req.setRepaymentEvery(15);
req.setLoanTermFrequency(45);
req.setTransactionProcessingStrategyCode("advanced-payment-allocation-strategy");
req.setLoanScheduleProcessingType(LoanScheduleType.PROGRESSIVE.toString());
req.setLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL.toString());
- });
+ }));
- disburseLoan(loanId, BigDecimal.valueOf(500.00), "01 January
2023");
+ disburseLoan(loanId.get(), BigDecimal.valueOf(500.00), "01 January
2023");
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(125.0, false, "16 January 2023"), //
installment(125.0, false, "31 January 2023"), //
installment(125.0, false, "15 February 2023")//
);
+ });
+ runAt("17 January 2023", () -> {
+ addRepaymentForLoan(loanId.get(), 50.0, "17 January 2023");
- updateBusinessDate("17 January 2023");
- addRepaymentForLoan(loanId, 50.0, "17 January 2023");
-
- updateBusinessDate("30 January 2023");
-
- reAmortizeLoan(loanId);
+ // verify transactions
+ verifyTransactions(loanId.get(), //
+ transaction(500.0, "Disbursement", "01 January 2023"), //
+ transaction(125.0, "Down Payment", "01 January 2023"), //
+ transaction(50.0, "Repayment", "17 January 2023") //
+ );
+ });
+ runAt("30 January 2023", () -> {
+ reAmortizeLoan(loanId.get());
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(50.0, true, "16 January 2023"), //
installment(162.5, false, "31 January 2023"), //
installment(162.5, false, "15 February 2023")//
);
+
+ // verify transactions
+ verifyTransactions(loanId.get(), //
+ transaction(500.0, "Disbursement", "01 January 2023"), //
+ transaction(125.0, "Down Payment", "01 January 2023"), //
+ transaction(50.0, "Repayment", "17 January 2023"), //
+ transaction(75.0, "Re-amortize", "30 January 2023") //
+ );
});
}
@@ -339,46 +348,52 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
Long clientId =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
Long loanProductId =
createLoanProductWithMultiDisbursalAndRepaymentsWithEnableDownPayment(3, 15);
- Long loanId = applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 500.0, 3, req -> {
+ loanId.set(applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 500.0, 3, req -> {
req.setRepaymentEvery(15);
req.setLoanTermFrequency(45);
req.setTransactionProcessingStrategyCode("advanced-payment-allocation-strategy");
req.setLoanScheduleProcessingType(LoanScheduleType.PROGRESSIVE.toString());
req.setLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL.toString());
- });
+ }));
- disburseLoan(loanId, BigDecimal.valueOf(500.00), "01 January
2023");
+ disburseLoan(loanId.get(), BigDecimal.valueOf(500.00), "01 January
2023");
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(125.0, false, "16 January 2023"), //
installment(125.0, false, "31 January 2023"), //
installment(125.0, false, "15 February 2023")//
);
+ });
+ runAt("05 January 2023", () -> {
+ addCharge(loanId.get(), false, 10.0, "05 January 2023");
- updateBusinessDate("05 January 2023");
- addCharge(loanId, false, 10.0, "05 January 2023");
-
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(125.0, 0.0, 10.0, 135.0, false, "16 January
2023"), //
installment(125.0, false, "31 January 2023"), //
installment(125.0, false, "15 February 2023")//
);
+ });
+ runAt("31 January 2023", () -> {
+ reAmortizeLoan(loanId.get());
- updateBusinessDate("31 January 2023");
-
- reAmortizeLoan(loanId);
-
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(0.0, 0.0, 10.0, 10.0, false, "16 January
2023"), //
installment(0.0, true, "31 January 2023"), //
installment(375.0, false, "15 February 2023")//
);
+
+ // verify transactions
+ verifyTransactions(loanId.get(), //
+ transaction(500.0, "Disbursement", "01 January 2023"), //
+ transaction(125.0, "Down Payment", "01 January 2023"), //
+ transaction(250.0, "Re-amortize", "31 January 2023") //
+ );
});
}
@@ -388,30 +403,30 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
Long clientId =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
Long loanProductId =
createLoanProductWithMultiDisbursalAndRepaymentsWithEnableDownPayment(3, 15);
- Long loanId = applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 500.0, 3, req -> {
+ loanId.set(applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 500.0, 3, req -> {
req.setRepaymentEvery(15);
req.setLoanTermFrequency(45);
req.setTransactionProcessingStrategyCode("advanced-payment-allocation-strategy");
req.setLoanScheduleProcessingType(LoanScheduleType.PROGRESSIVE.toString());
req.setLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL.toString());
- });
+ }));
- disburseLoan(loanId, BigDecimal.valueOf(500.00), "01 January
2023");
+ disburseLoan(loanId.get(), BigDecimal.valueOf(500.00), "01 January
2023");
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(125.0, false, "16 January 2023"), //
installment(125.0, false, "31 January 2023"), //
installment(125.0, false, "15 February 2023")//
);
+ });
+ runAt("01 February 2023", () -> {
+ addCharge(loanId.get(), false, 10.0, "27 February 2023");
- updateBusinessDate("01 February 2023");
- addCharge(loanId, false, 10.0, "27 February 2023");
-
- reAmortizeLoan(loanId);
+ reAmortizeLoan(loanId.get());
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(0.0, true, "16 January 2023"), //
@@ -419,6 +434,13 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
installment(375.0, false, "15 February 2023"), //
installment(0.0, 0.0, 10.0, false, "27 February 2023") //
);
+
+ // verify transactions
+ verifyTransactions(loanId.get(), //
+ transaction(500.0, "Disbursement", "01 January 2023"), //
+ transaction(125.0, "Down Payment", "01 January 2023"), //
+ transaction(250.0, "Re-amortize", "01 February 2023") //
+ );
});
}
@@ -428,38 +450,61 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
Long clientId =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
Long loanProductId =
createLoanProductWithMultiDisbursalAndRepaymentsWithEnableDownPayment(3, 15);
- Long loanId = applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 500.0, 3, req -> {
+ loanId.set(applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 500.0, 3, req -> {
req.setRepaymentEvery(15);
req.setLoanTermFrequency(45);
req.setTransactionProcessingStrategyCode("advanced-payment-allocation-strategy");
req.setLoanScheduleProcessingType(LoanScheduleType.PROGRESSIVE.toString());
req.setLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL.toString());
- });
+ }));
- disburseLoan(loanId, BigDecimal.valueOf(500.00), "01 January
2023");
+ disburseLoan(loanId.get(), BigDecimal.valueOf(500.00), "01 January
2023");
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(125.0, false, "16 January 2023"), //
installment(125.0, false, "31 January 2023"), //
installment(125.0, false, "15 February 2023")//
);
+ });
+ runAt("01 February 2023", () -> {
+ reAmortizeLoan(loanId.get());
- updateBusinessDate("01 February 2023");
+ verifyRepaymentSchedule(loanId.get(), //
+ installment(0, null, "01 January 2023"), //
+ installment(125.0, true, "01 January 2023"), //
+ installment(0.0, true, "16 January 2023"), //
+ installment(0.0, true, "31 January 2023"), //
+ installment(375.0, false, "15 February 2023")//
+ );
- reAmortizeLoan(loanId);
+ // verify transactions
+ verifyTransactions(loanId.get(), //
+ transaction(500.0, "Disbursement", "01 January 2023"), //
+ transaction(125.0, "Down Payment", "01 January 2023"), //
+ transaction(250.0, "Re-amortize", "01 February 2023") //
+ );
- updateBusinessDate("01 February 2023");
- addRepaymentForLoan(loanId, 125.0, "15 January 2023");
+ });
+ runAt("02 February 2023", () -> {
+ addRepaymentForLoan(loanId.get(), 125.0, "15 January 2023");
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(125.0, true, "16 January 2023"), //
installment(0.0, true, "31 January 2023"), //
installment(250.0, false, "15 February 2023")//
);
+
+ // verify transactions
+ verifyTransactions(loanId.get(), //
+ transaction(500.0, "Disbursement", "01 January 2023"), //
+ transaction(125.0, "Down Payment", "01 January 2023"), //
+ transaction(125.0, "Repayment", "15 January 2023"), //
+ transaction(125.0, "Re-amortize", "01 February 2023") //
+ );
});
}
@@ -469,32 +514,47 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
Long clientId =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
Long loanProductId =
createLoanProductWithMultiDisbursalAndRepaymentsWithEnableDownPayment(3, 15);
- Long loanId = applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 500.0, 3, req -> {
+ loanId.set(applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 500.0, 3, req -> {
req.setRepaymentEvery(15);
req.setLoanTermFrequency(45);
req.setTransactionProcessingStrategyCode("advanced-payment-allocation-strategy");
req.setLoanScheduleProcessingType(LoanScheduleType.PROGRESSIVE.toString());
req.setLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL.toString());
- });
+ }));
- disburseLoan(loanId, BigDecimal.valueOf(500.00), "01 January
2023");
+ disburseLoan(loanId.get(), BigDecimal.valueOf(500.00), "01 January
2023");
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(125.0, false, "16 January 2023"), //
installment(125.0, false, "31 January 2023"), //
installment(125.0, false, "15 February 2023")//
);
+ });
+ AtomicLong repaymentTransactionId = new AtomicLong();
+ runAt("15 January 2023", () -> {
+ repaymentTransactionId.set(addRepaymentForLoan(loanId.get(),
125.0, "15 January 2023"));
- updateBusinessDate("15 January 2023");
- Long repaymentTransactionId = addRepaymentForLoan(loanId, 125.0,
"15 January 2023");
-
- updateBusinessDate("01 February 2023");
+ verifyRepaymentSchedule(loanId.get(), //
+ installment(0, null, "01 January 2023"), //
+ installment(125.0, true, "01 January 2023"), //
+ installment(125.0, true, "16 January 2023"), //
+ installment(125.0, false, "31 January 2023"), //
+ installment(125.0, false, "15 February 2023")//
+ );
- reAmortizeLoan(loanId);
+ // verify transactions
+ verifyTransactions(loanId.get(), //
+ transaction(500.0, "Disbursement", "01 January 2023"), //
+ transaction(125.0, "Down Payment", "01 January 2023"), //
+ transaction(125.0, "Repayment", "15 January 2023") //
+ );
+ });
+ runAt("01 February 2023", () -> {
+ reAmortizeLoan(loanId.get());
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(125.0, true, "16 January 2023"), //
@@ -502,15 +562,31 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
installment(250.0, false, "15 February 2023")//
);
+ // verify transactions
+ verifyTransactions(loanId.get(), //
+ transaction(500.0, "Disbursement", "01 January 2023"), //
+ transaction(125.0, "Down Payment", "01 January 2023"), //
+ transaction(125.0, "Repayment", "15 January 2023"), //
+ transaction(125.0, "Re-amortize", "01 February 2023") //
+ );
+
loanTransactionHelper.reverseRepayment(loanId.intValue(),
repaymentTransactionId.intValue(), "01 February 2023");
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(0.0, true, "16 January 2023"), //
installment(0.0, true, "31 January 2023"), //
installment(375.0, false, "15 February 2023")//
);
+
+ // verify transactions
+ verifyTransactions(loanId.get(), //
+ transaction(500.0, "Disbursement", "01 January 2023"), //
+ transaction(125.0, "Down Payment", "01 January 2023"), //
+ transaction(125.0, "Repayment", "15 January 2023"), //
+ transaction(250.0, "Re-amortize", "01 February 2023") //
+ );
});
}
@@ -520,29 +596,29 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
Long clientId =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
Long loanProductId =
createLoanProductWithMultiDisbursalAndRepaymentsWithEnableDownPayment(3, 15);
- Long loanId = applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 500.0, 3, req -> {
+ loanId.set(applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 500.0, 3, req -> {
req.setRepaymentEvery(15);
req.setLoanTermFrequency(45);
req.setTransactionProcessingStrategyCode("advanced-payment-allocation-strategy");
req.setLoanScheduleProcessingType(LoanScheduleType.PROGRESSIVE.toString());
req.setLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL.toString());
- });
+ }));
- disburseLoan(loanId, BigDecimal.valueOf(500.00), "01 January
2023");
+ disburseLoan(loanId.get(), BigDecimal.valueOf(500.00), "01 January
2023");
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(125.0, false, "16 January 2023"), //
installment(125.0, false, "31 January 2023"), //
installment(125.0, false, "15 February 2023")//
);
+ });
+ runAt("01 February 2023", () -> {
- updateBusinessDate("01 February 2023");
-
- reAmortizeLoan(loanId);
+ reAmortizeLoan(loanId.get());
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(0.0, true, "16 January 2023"), //
@@ -550,17 +626,31 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
installment(375.0, false, "15 February 2023")//
);
- updateBusinessDate("02 February 2023");
+ // verify transactions
+ verifyTransactions(loanId.get(), //
+ transaction(500.0, "Disbursement", "01 January 2023"), //
+ transaction(125.0, "Down Payment", "01 January 2023"), //
+ transaction(250.0, "Re-amortize", "01 February 2023") //
+ );
+ });
+ runAt("02 February 2023", () -> {
- undoReAmortizeLoan(loanId);
+ undoReAmortizeLoan(loanId.get());
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(125.0, false, "16 January 2023"), //
installment(125.0, false, "31 January 2023"), //
installment(125.0, false, "15 February 2023")//
);
+
+ // verify transactions
+ verifyTransactions(loanId.get(), //
+ transaction(500.0, "Disbursement", "01 January 2023"), //
+ transaction(125.0, "Down Payment", "01 January 2023"), //
+ reversedTransaction(250.0, "Re-amortize", "01 February
2023") //
+ );
});
}
@@ -570,17 +660,17 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
Long clientId =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
Long loanProductId =
createLoanProductWithMultiDisbursalAndRepaymentsWithEnableDownPayment(4, 15,
BigDecimal.valueOf(20));
- Long loanId = applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 500.0, 4, req -> {
+ loanId.set(applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 500.0, 4, req -> {
req.setRepaymentEvery(15);
req.setLoanTermFrequency(60);
req.setTransactionProcessingStrategyCode("advanced-payment-allocation-strategy");
req.setLoanScheduleProcessingType(LoanScheduleType.PROGRESSIVE.toString());
req.setLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL.toString());
- });
+ }));
- disburseLoan(loanId, BigDecimal.valueOf(500.00), "01 January
2023");
+ disburseLoan(loanId.get(), BigDecimal.valueOf(500.00), "01 January
2023");
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(100.0, true, "01 January 2023"), //
installment(100.0, false, "16 January 2023"), //
@@ -588,12 +678,11 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
installment(100.0, false, "15 February 2023"), //
installment(100.0, false, "02 March 2023")//
);
+ });
+ runAt("17 January 2023", () -> {
+ reAmortizeLoan(loanId.get());
- updateBusinessDate("17 January 2023");
-
- reAmortizeLoan(loanId);
-
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(100.0, true, "01 January 2023"), //
installment(0.0, true, "16 January 2023"), //
@@ -601,6 +690,13 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
installment(133.33, false, "15 February 2023"), //
installment(133.34, false, "02 March 2023")//
);
+
+ // verify transactions
+ verifyTransactions(loanId.get(), //
+ transaction(500.0, "Disbursement", "01 January 2023"), //
+ transaction(100.0, "Down Payment", "01 January 2023"), //
+ transaction(100.0, "Re-amortize", "17 January 2023") //
+ );
});
}
@@ -610,31 +706,32 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
Long clientId =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
Long loanProductId =
createLoanProductWithMultiDisbursalAndRepaymentsWithEnableDownPayment(3, 15);
- Long loanId = applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 1000.0, 3, req -> {
+ loanId.set(applyAndApproveLoan(clientId, loanProductId, "01
January 2023", 1000.0, 3, req -> {
req.setRepaymentEvery(15);
req.setLoanTermFrequency(45);
req.setTransactionProcessingStrategyCode("advanced-payment-allocation-strategy");
req.setLoanScheduleProcessingType(LoanScheduleType.PROGRESSIVE.toString());
req.setLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL.toString());
- });
+ }));
- disburseLoan(loanId, BigDecimal.valueOf(500.00), "01 January
2023");
+ disburseLoan(loanId.get(), BigDecimal.valueOf(500.00), "01 January
2023");
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(125.0, false, "16 January 2023"), //
installment(125.0, false, "31 January 2023"), //
installment(125.0, false, "15 February 2023") //
);
+ });
+ runAt("16 January 2023", () -> {
+ addCharge(loanId.get(), false, 10.0, "16 January 2023");
+ });
+ runAt("25 January 2023", () -> {
- updateBusinessDate("16 January 2023");
- addCharge(loanId, false, 10.0, "16 January 2023");
-
- updateBusinessDate("25 January 2023");
- reAmortizeLoan(loanId);
+ reAmortizeLoan(loanId.get());
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(0.0, 0.0, 10.0, 10.0, false, "16 January
2023"), //
@@ -642,11 +739,17 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
installment(187.5, false, "15 February 2023") //
);
- updateBusinessDate("26 January 2023");
-
- disburseLoan(loanId, BigDecimal.valueOf(500.00), "26 January
2023");
+ // verify transactions
+ verifyTransactions(loanId.get(), //
+ transaction(500.0, "Disbursement", "01 January 2023"), //
+ transaction(125.0, "Down Payment", "01 January 2023"), //
+ transaction(125.0, "Re-amortize", "25 January 2023") //
+ );
+ });
+ runAt("26 January 2023", () -> {
+ disburseLoan(loanId.get(), BigDecimal.valueOf(500.00), "26 January
2023");
- verifyRepaymentSchedule(loanId, //
+ verifyRepaymentSchedule(loanId.get(), //
installment(0, null, "01 January 2023"), //
installment(125.0, true, "01 January 2023"), //
installment(0.0, 0.0, 10.0, 0.0, true, "16 January 2023"),
//
@@ -655,6 +758,42 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
installment(375.0, false, "31 January 2023"), //
installment(375.0, false, "15 February 2023") //
);
+
+ // verify transactions
+ verifyTransactions(loanId.get(), //
+ transaction(500.0, "Disbursement", "01 January 2023"), //
+ transaction(125.0, "Down Payment", "01 January 2023"), //
+ transaction(125.0, "Re-amortize", "25 January 2023"), //
+ transaction(500.0, "Disbursement", "26 January 2023"), //
+ transaction(125.0, "Down Payment", "26 January 2023") //
+ );
+ });
+
+ runAt("27 January 2023", () -> {
+ disburseLoan(loanId.get(), BigDecimal.valueOf(100.0), "10 January
2023");
+
+ verifyRepaymentSchedule(loanId.get(), //
+ installment(0, null, "01 January 2023"), //
+ installment(125.0, true, "01 January 2023"), //
+ installment(100.0, null, "10 January 2023"), //
+ installment(25.0, true, "10 January 2023"), //
+ installment(0.0, 0.0, 10.0, 0.0, true, "16 January 2023"),
//
+ installment(500.0, null, "26 January 2023"), //
+ installment(125.0, false, "26 January 2023"), //
+ installment(412.5, false, "31 January 2023"), //
+ installment(412.5, false, "15 February 2023") //
+ );
+
+ // verify transactions
+ verifyTransactions(loanId.get(), //
+ transaction(500.0, "Disbursement", "01 January 2023"), //
+ transaction(125.0, "Down Payment", "01 January 2023"), //
+ transaction(100.0, "Disbursement", "10 January 2023"), //
+ transaction(25.0, "Down Payment", "10 January 2023"), //
+ transaction(150.0, "Re-amortize", "25 January 2023"), //
+ transaction(500.0, "Disbursement", "26 January 2023"), //
+ transaction(125.0, "Down Payment", "26 January 2023") //
+ );
});
}
@@ -665,19 +804,11 @@ public class LoanReAmortizationIntegrationTest extends
BaseLoanIntegrationTest {
private Long
createLoanProductWithMultiDisbursalAndRepaymentsWithEnableDownPayment(int
numberOfInstallments, int repaymentEvery,
BigDecimal downPaymentPercentage) {
- boolean multiDisburseEnabled = true;
PostLoanProductsRequest product =
createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation();
- product.setMultiDisburseLoan(multiDisburseEnabled);
+ product.setMultiDisburseLoan(true);
product.setNumberOfRepayments(numberOfInstallments);
product.setRepaymentEvery(repaymentEvery);
- if (!multiDisburseEnabled) {
- product.disallowExpectedDisbursements(null);
- product.setAllowApprovedDisbursedAmountsOverApplied(null);
- product.overAppliedCalculationType(null);
- product.overAppliedNumber(null);
- }
-
product.setEnableDownPayment(true);
product.setDisbursedAmountPercentageForDownPayment(downPaymentPercentage);
product.setEnableAutoRepaymentForDownPayment(true);