diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanReAgingStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanReAgingStepDef.java index abc8621a3..a8c25005c 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanReAgingStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanReAgingStepDef.java @@ -413,7 +413,7 @@ public class LoanReAgingStepDef extends AbstractStepDef { } } - @Then("Loan Repayment schedule preview has the following data in Total row:") + @Then("Loan Re-Aged Repayment schedule preview has the following data in Total row:") public void loanRepaymentScheduleAmountCheck(DataTable table) { List> data = table.asLists(); List header = data.get(0); diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanReAmortizationStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanReAmortizationStepDef.java index 7e70c4867..7c19375d2 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanReAmortizationStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanReAmortizationStepDef.java @@ -19,16 +19,28 @@ package org.apache.fineract.test.stepdef.loan; import static org.apache.fineract.client.feign.util.FeignCalls.ok; +import static org.assertj.core.api.Assertions.assertThat; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import io.cucumber.datatable.DataTable; import io.cucumber.java.en.Then; import io.cucumber.java.en.When; -import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import org.apache.fineract.client.feign.FineractFeignClient; +import org.apache.fineract.client.models.LoanScheduleData; +import org.apache.fineract.client.models.LoanSchedulePeriodData; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse; import org.apache.fineract.client.models.PostLoansResponse; import org.apache.fineract.test.factory.LoanRequestFactory; +import org.apache.fineract.test.helper.ErrorMessageHelper; +import org.apache.fineract.test.helper.Utils; import org.apache.fineract.test.messaging.EventAssertion; import org.apache.fineract.test.messaging.event.loan.LoanReAmortizeEvent; import org.apache.fineract.test.stepdef.AbstractStepDef; @@ -37,6 +49,9 @@ import org.springframework.beans.factory.annotation.Autowired; public class LoanReAmortizationStepDef extends AbstractStepDef { + private static final String DATE_FORMAT = "dd MMMM yyyy"; + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern(DATE_FORMAT); + @Autowired private FineractFeignClient fineractClient; @@ -44,7 +59,7 @@ public class LoanReAmortizationStepDef extends AbstractStepDef { private EventAssertion eventAssertion; @When("When Admin creates a Loan re-amortization transaction on current business date") - public void createLoanReAmortization() throws IOException { + public void createLoanReAmortization() { PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.getLoanId(); @@ -56,7 +71,7 @@ public class LoanReAmortizationStepDef extends AbstractStepDef { } @When("When Admin creates a Loan re-amortization transaction on current business date by loan external ID") - public void createLoanReAmortizationByLoanExternalId() throws IOException { + public void createLoanReAmortizationByLoanExternalId() { PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); String loanExternalId = loanResponse.getResourceExternalId(); @@ -68,7 +83,7 @@ public class LoanReAmortizationStepDef extends AbstractStepDef { } @When("When Admin undo Loan re-amortization transaction on current business date") - public void undoLoanReAmortization() throws IOException { + public void undoLoanReAmortization() { PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.getLoanId(); @@ -84,4 +99,157 @@ public class LoanReAmortizationStepDef extends AbstractStepDef { eventAssertion.assertEventRaised(LoanReAmortizeEvent.class, loanId); } + + @When("Admin creates a Loan re-amortization preview by Loan external ID with the following data:") + public void createReAmortizedPreviewByLoanExternalId(final DataTable table) { + final LoanScheduleData response = reAmortizedPreviewByLoanExternalId(table); + testContext().set(TestContextKey.LOAN_REAMORTIZATION_PREVIEW_RESPONSE, response); + } + + @Then("Loan Re-Amortization Repayment schedule preview has the following data in Total row:") + public void loanRepaymentDScheduleAmountCheck(final DataTable table) { + final List> data = table.asLists(); + final List header = data.get(0); + final List expectedValues = data.get(1); + final LoanScheduleData scheduleResponse = testContext().get(TestContextKey.LOAN_REAMORTIZATION_PREVIEW_RESPONSE); + validateRepaymentScheduleTotal(header, scheduleResponse, expectedValues); + } + + @Then("Loan Re-Amortization Repayment schedule preview has {int} periods, with the following data for periods:") + public void loanRepaymentSchedulePreviewPeriodsCheck(final int linesExpected, final DataTable table) { + final LoanScheduleData scheduleResponse = testContext().get(TestContextKey.LOAN_REAMORTIZATION_PREVIEW_RESPONSE); + final List repaymentPeriods = scheduleResponse.getPeriods(); + + final PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); + final String resourceId = String.valueOf(loanResponse.getLoanId()); + final List> data = table.asLists(); + final int nrLines = data.size(); + final int linesActual = (int) repaymentPeriods.stream().filter(r -> r.getPeriod() != null).count(); + + for (int i = 1; i < nrLines; i++) { + List expectedValues = data.get(i); + String dueDateExpected = expectedValues.get(2); + + List> actualValuesList = repaymentPeriods.stream() + .filter(r -> dueDateExpected.equals(FORMATTER.format(r.getDueDate()))) + .map(r -> fetchValuesOfRepaymentSchedule(data.get(0), r)).collect(Collectors.toList()); + + boolean containsExpectedValues = actualValuesList.stream().anyMatch(actualValues -> actualValues.equals(expectedValues)); + assertThat(containsExpectedValues) + .as(ErrorMessageHelper.wrongValueInLineInRepaymentSchedule(resourceId, i, actualValuesList, expectedValues)).isTrue(); + + assertThat(linesActual).as(ErrorMessageHelper.wrongNumberOfLinesInRepaymentSchedule(resourceId, linesActual, linesExpected)) + .isEqualTo(linesExpected); + } + } + + private LoanScheduleData reAmortizedPreviewByLoanExternalId(final DataTable table) { + final PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); + final String loanExternalId = loanResponse.getResourceExternalId(); + + final List data = table.asLists().get(1); + final String reAmortizationInterestHandling = data.getFirst(); + + final Map queryParams = Map.of("reAmortizationInterestHandling", reAmortizationInterestHandling); + return ok(() -> fineractClient.loanTransactions().previewReAmortizationSchedule1(loanExternalId, queryParams)); + } + + @SuppressFBWarnings("SF_SWITCH_NO_DEFAULT") + private void validateRepaymentScheduleTotal(final List header, final LoanScheduleData repaymentSchedule, + final List expectedAmounts) { + Double paidActual = 0.0; + final List periods = repaymentSchedule.getPeriods(); + for (LoanSchedulePeriodData period : periods) { + if (null != period.getTotalPaidForPeriod()) { + paidActual += period.getTotalPaidForPeriod().doubleValue(); + } + } + final BigDecimal paidActualBd = new BigDecimal(paidActual).setScale(2, RoundingMode.HALF_DOWN); + + for (int i = 0; i < header.size(); i++) { + final String headerName = header.get(i); + final String expectedValue = expectedAmounts.get(i); + switch (headerName) { + case "Principal due" -> assertThat(repaymentSchedule.getTotalPrincipalExpected())// + .as(ErrorMessageHelper.wrongAmountInRepaymentSchedulePrincipal( + repaymentSchedule.getTotalPrincipalExpected().doubleValue(), Double.valueOf(expectedValue)))// + .isEqualByComparingTo(new BigDecimal(expectedValue));// + case "Interest" -> assertThat(repaymentSchedule.getTotalInterestCharged())// + .as(ErrorMessageHelper.wrongAmountInRepaymentScheduleInterest( + repaymentSchedule.getTotalInterestCharged().doubleValue(), Double.valueOf(expectedValue)))// + .isEqualByComparingTo(new BigDecimal(expectedValue));// + case "Fees" -> assertThat(repaymentSchedule.getTotalFeeChargesCharged())// + .as(ErrorMessageHelper.wrongAmountInRepaymentScheduleFees( + repaymentSchedule.getTotalFeeChargesCharged().doubleValue(), Double.valueOf(expectedValue)))// + .isEqualByComparingTo(new BigDecimal(expectedValue));// + case "Penalties" -> assertThat(repaymentSchedule.getTotalPenaltyChargesCharged())// + .as(ErrorMessageHelper.wrongAmountInRepaymentSchedulePenalties( + repaymentSchedule.getTotalPenaltyChargesCharged().doubleValue(), Double.valueOf(expectedValue)))// + .isEqualByComparingTo(new BigDecimal(expectedValue));// + case "Due" -> assertThat(repaymentSchedule.getTotalRepaymentExpected())// + .as(ErrorMessageHelper.wrongAmountInRepaymentScheduleDue( + repaymentSchedule.getTotalRepaymentExpected().doubleValue(), Double.valueOf(expectedValue)))// + .isEqualByComparingTo(new BigDecimal(expectedValue));// + case "Paid" -> assertThat(paidActualBd)// + .as(ErrorMessageHelper.wrongAmountInRepaymentSchedulePaid(paidActualBd.doubleValue(), + Double.valueOf(expectedValue)))// + .isEqualByComparingTo(new BigDecimal(expectedValue));// + case "In advance" -> assertThat(repaymentSchedule.getTotalPaidInAdvance())// + .as(ErrorMessageHelper.wrongAmountInRepaymentScheduleInAdvance( + repaymentSchedule.getTotalPaidInAdvance().doubleValue(), Double.valueOf(expectedValue)))// + .isEqualByComparingTo(new BigDecimal(expectedValue));// + case "Late" -> assertThat(repaymentSchedule.getTotalPaidLate())// + .as(ErrorMessageHelper.wrongAmountInRepaymentScheduleLate(repaymentSchedule.getTotalPaidLate().doubleValue(), + Double.valueOf(expectedValue)))// + .isEqualByComparingTo(new BigDecimal(expectedValue));// + case "Waived" -> assertThat(repaymentSchedule.getTotalWaived())// + .as(ErrorMessageHelper.wrongAmountInRepaymentScheduleWaived(repaymentSchedule.getTotalWaived().doubleValue(), + Double.valueOf(expectedValue)))// + .isEqualByComparingTo(new BigDecimal(expectedValue));// + case "Outstanding" -> assertThat(repaymentSchedule.getTotalOutstanding())// + .as(ErrorMessageHelper.wrongAmountInRepaymentScheduleOutstanding( + repaymentSchedule.getTotalOutstanding().doubleValue(), Double.valueOf(expectedValue)))// + .isEqualByComparingTo(new BigDecimal(expectedValue));// + } + } + } + + private List fetchValuesOfRepaymentSchedule(final List header, final LoanSchedulePeriodData repaymentPeriod) { + final List actualValues = new ArrayList<>(); + for (String headerName : header) { + switch (headerName) { + case "Nr" -> actualValues.add(repaymentPeriod.getPeriod() == null ? null : String.valueOf(repaymentPeriod.getPeriod())); + case "Days" -> + actualValues.add(repaymentPeriod.getDaysInPeriod() == null ? null : String.valueOf(repaymentPeriod.getDaysInPeriod())); + case "Date" -> + actualValues.add(repaymentPeriod.getDueDate() == null ? null : FORMATTER.format(repaymentPeriod.getDueDate())); + case "Paid date" -> actualValues.add(repaymentPeriod.getObligationsMetOnDate() == null ? null + : FORMATTER.format(repaymentPeriod.getObligationsMetOnDate())); + case "Balance of loan" -> actualValues.add(repaymentPeriod.getPrincipalLoanBalanceOutstanding() == null ? null + : new Utils.DoubleFormatter(repaymentPeriod.getPrincipalLoanBalanceOutstanding().doubleValue()).format()); + case "Principal due" -> actualValues.add(repaymentPeriod.getPrincipalDue() == null ? null + : new Utils.DoubleFormatter(repaymentPeriod.getPrincipalDue().doubleValue()).format()); + case "Interest" -> actualValues.add(repaymentPeriod.getInterestDue() == null ? null + : new Utils.DoubleFormatter(repaymentPeriod.getInterestDue().doubleValue()).format()); + case "Fees" -> actualValues.add(repaymentPeriod.getFeeChargesDue() == null ? null + : new Utils.DoubleFormatter(repaymentPeriod.getFeeChargesDue().doubleValue()).format()); + case "Penalties" -> actualValues.add(repaymentPeriod.getPenaltyChargesDue() == null ? null + : new Utils.DoubleFormatter(repaymentPeriod.getPenaltyChargesDue().doubleValue()).format()); + case "Due" -> actualValues.add(repaymentPeriod.getTotalDueForPeriod() == null ? null + : new Utils.DoubleFormatter(repaymentPeriod.getTotalDueForPeriod().doubleValue()).format()); + case "Paid" -> actualValues.add(repaymentPeriod.getTotalPaidForPeriod() == null ? null + : new Utils.DoubleFormatter(repaymentPeriod.getTotalPaidForPeriod().doubleValue()).format()); + case "In advance" -> actualValues.add(repaymentPeriod.getTotalPaidInAdvanceForPeriod() == null ? null + : new Utils.DoubleFormatter(repaymentPeriod.getTotalPaidInAdvanceForPeriod().doubleValue()).format()); + case "Late" -> actualValues.add(repaymentPeriod.getTotalPaidLateForPeriod() == null ? null + : new Utils.DoubleFormatter(repaymentPeriod.getTotalPaidLateForPeriod().doubleValue()).format()); + case "Waived" -> actualValues.add(repaymentPeriod.getTotalWaivedForPeriod() == null ? null + : new Utils.DoubleFormatter(repaymentPeriod.getTotalWaivedForPeriod().doubleValue()).format()); + case "Outstanding" -> actualValues.add(repaymentPeriod.getTotalOutstandingForPeriod() == null ? null + : new Utils.DoubleFormatter(repaymentPeriod.getTotalOutstandingForPeriod().doubleValue()).format()); + default -> throw new IllegalStateException(String.format("Header name %s cannot be found", headerName)); + } + } + return actualValues; + } } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java index 3ccaa8a6a..983279900 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java @@ -52,6 +52,7 @@ public abstract class TestContextKey { public static final String LOAN_REAGING_UNDO_RESPONSE = "loanReAgingUndoResponse"; public static final String LOAN_REAGING_PREVIEW_RESPONSE = "loanReAgingPreviewResponse"; public static final String LOAN_REAMORTIZATION_RESPONSE = "loanReAmortizationResponse"; + public static final String LOAN_REAMORTIZATION_PREVIEW_RESPONSE = "loanReAmortizationPreviewResponse"; public static final String LOAN_REAMORTIZATION_UNDO_RESPONSE = "loanReAmortizationUndoResponse"; public static final String BUSINESS_DATE_RESPONSE = "businessDateResponse"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1 = "loanProductCreateResponseLP1"; diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanReAging.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanReAging.feature index e8e467941..e23aaf6c5 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanReAging.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanReAging.feature @@ -2300,7 +2300,7 @@ Feature: LoanReAging | 7 | 31 | 15 June 2024 | | 333.32 | 166.67 | 0.0 | 0.0 | 0.0 | 166.67 | 0.0 | 0.0 | 0.0 | 166.67 | | 8 | 30 | 15 July 2024 | | 166.65 | 166.67 | 0.0 | 0.0 | 0.0 | 166.67 | 0.0 | 0.0 | 0.0 | 166.67 | | 9 | 31 | 15 August 2024 | | 0.0 | 166.65 | 0.0 | 0.0 | 0.0 | 166.65 | 0.0 | 0.0 | 0.0 | 166.65 | - Then Loan Repayment schedule preview has the following data in Total row: + Then Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 1000.0 | 0.0 | 0.0 | 0.0 | 1000.0 | 0.0 | 0.0 | 0.0 | 1000.0 | @@ -2436,7 +2436,7 @@ Feature: LoanReAging | 5 | 30 | 15 May 2025 | | 309.0 | 156.0 | 0.0 | 0.0 | 0.0 | 156.0 | 0.0 | 0.0 | 0.0 | 156.0 | | 6 | 31 | 15 June 2025 | | 153.0 | 156.0 | 0.0 | 0.0 | 0.0 | 156.0 | 0.0 | 0.0 | 0.0 | 156.0 | | 7 | 30 | 15 July 2025 | | 0.0 | 153.0 | 0.0 | 0.0 | 0.0 | 153.0 | 0.0 | 0.0 | 0.0 | 153.0 | - Then Loan Repayment schedule preview has the following data in Total row: + Then Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 1100.0 | 0.0 | 0.0 | 0.0 | 1100.0 | 167.0 | 0.0 | 167.0 | 933.0 | @@ -2521,7 +2521,7 @@ Feature: LoanReAging | | | 01 January 2025 | | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | | | | | 1 | 31 | 01 February 2025 | 03 February 2025 | 833.0 | 167.0 | 0.0 | 0.0 | 0.0 | 167.0 | 167.0 | 0.0 | 167.0 | 0.0 | | 2 | 14 | 15 February 2025 | | 0.0 | 933.0 | 0.0 | 0.0 | 0.0 | 933.0 | 0.0 | 0.0 | 0.0 | 933.0 | - Then Loan Repayment schedule preview has the following data in Total row: + Then Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 1100.0 | 0.0 | 0.0 | 0.0 | 1100.0 | 167.0 | 0.0 | 167.0 | 933.0 | @@ -2653,7 +2653,7 @@ Feature: LoanReAging | | | 10 February 2025 | | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | | | | | 2 | 14 | 15 February 2025 | | 750.0 | 750.0 | 0.0 | 0.0 | 0.0 | 750.0 | 0.0 | 0.0 | 0.0 | 750.0 | | 3 | 28 | 15 March 2025 | | 0.0 | 750.0 | 0.0 | 0.0 | 0.0 | 750.0 | 0.0 | 0.0 | 0.0 | 750.0 | - Then Loan Repayment schedule preview has the following data in Total row: + Then Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 1500.0 | 0.0 | 0.0 | 0.0 | 1500.0 | 0.0 | 0.0 | 0.0 | 1500.0 | @@ -3245,7 +3245,7 @@ Feature: LoanReAging | 11 | 30 | 15 October 2024 | | 200.0 | 100.0 | 0.0 | 0.0 | 20.0 | 120.0 | 0.0 | 0.0 | 0.0 | 120.0 | | 12 | 31 | 15 November 2024 | | 100.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | | 13 | 30 | 15 December 2024 | | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | - Then Loan Repayment schedule preview has the following data in Total row: + Then Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 1000.0 | 0.0 | 0.0 | 20.0 | 1020.0 | 0.0 | 0.0 | 0.0 | 1020.0 | @@ -3328,7 +3328,7 @@ Feature: LoanReAging | 4 | 14 | 15 March 2024 | | 500.0 | 500.0 | 0.0 | 0.0 | 0.0 | 500.0 | 0.0 | 0.0 | 0.0 | 500.0 | | 5 | 31 | 15 April 2024 | | 0.0 | 500.0 | 0.0 | 0.0 | 0.0 | 500.0 | 0.0 | 0.0 | 0.0 | 500.0 | | 6 | 200 | 01 November 2024 | | 0.0 | 0.0 | 0.0 | 0.0 | 50.0 | 50.0 | 0.0 | 0.0 | 0.0 | 50.0 | - Then Loan Repayment schedule preview has the following data in Total row: + Then Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 1000.0 | 0.0 | 0.0 | 50.0 | 1050.0 | 0.0 | 0.0 | 0.0 | 1050.0 | diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanReAgingPreview.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanReAgingPreview.feature index d31754af1..cb5924573 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanReAgingPreview.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanReAgingPreview.feature @@ -34,7 +34,7 @@ Feature: LoanReAgingPreview | 5 | 14 | 15 April 2025 | | 666.67 | 333.33 | 0.0 | 0.0 | 0.0 | 333.33 | 0.0 | 0.0 | 0.0 | 333.33 | | 6 | 30 | 15 May 2025 | | 333.34 | 333.33 | 0.0 | 0.0 | 0.0 | 333.33 | 0.0 | 0.0 | 0.0 | 333.33 | | 7 | 31 | 15 June 2025 | | 0.0 | 333.34 | 0.0 | 0.0 | 0.0 | 333.34 | 0.0 | 0.0 | 0.0 | 333.34 | - Then Loan Repayment schedule preview has the following data in Total row: + Then Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 1000.0 | 0.0 | 0.0 | 0.0 | 1000.0 | 0.0 | 0.0 | 0.0 | 1000.0 | Then Loan Repayment schedule has 4 periods, with the following data for periods: @@ -149,7 +149,7 @@ Feature: LoanReAgingPreview | 3 | 28 | 01 March 2025 | 01 April 2025 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | | 4 | 31 | 01 April 2025 | | 0.0 | 1000.0 | 0.0 | 0.0 | 0.0 | 1000.0 | 0.0 | 0.0 | 0.0 | 1000.0 | | 5 | 32 | 03 May 2025 | | 0.0 | 0.0 | 0.0 | 0.0 | 10.0 | 10.0 | 0.0 | 0.0 | 0.0 | 10.0 | - And Loan Repayment schedule preview has the following data in Total row: + And Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 1000.0 | 0.0 | 0.0 | 10.0 | 1010.0 | 0.0 | 0.0 | 0.0 | 1010.0 | And Loan Repayment schedule has 5 periods, with the following data for periods: @@ -201,7 +201,7 @@ Feature: LoanReAgingPreview | 3 | 28 | 01 March 2025 | 01 April 2025 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | | 4 | 31 | 01 April 2025 | | 0.0 | 750.0 | 0.0 | 0.0 | 0.0 | 750.0 | 0.0 | 0.0 | 0.0 | 750.0 | | 5 | 32 | 03 May 2025 | | 0.0 | 0.0 | 0.0 | 0.0 | 10.0 | 10.0 | 0.0 | 0.0 | 0.0 | 10.0 | - And Loan Repayment schedule preview has the following data in Total row: + And Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 1000.0 | 0.0 | 0.0 | 10.0 | 1010.0 | 250.0 | 0.0 | 250.0 | 760.0 | And Loan Repayment schedule has 5 periods, with the following data for periods: @@ -254,7 +254,7 @@ Feature: LoanReAgingPreview | 3 | 15 | 31 January 2025 | 15 February 2025 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | | 4 | 15 | 15 February 2025 | 20 March 2025 | 0.0 | 750.0 | 0.0 | 0.0 | 0.0 | 750.0 | 750.0 | 0.0 | 750.0 | 0.0 | | 5 | 33 | 20 March 2025 | | 0.0 | 0.0 | 0.0 | 0.0 | 10.0 | 10.0 | 0.0 | 0.0 | 0.0 | 10.0 | - And Loan Repayment schedule preview has the following data in Total row: + And Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 1000.0 | 0.0 | 0.0 | 10.0 | 1010.0 | 1000.0 | 0.0 | 750.0 | 10.0 | And Loan Repayment schedule has 5 periods, with the following data for periods: @@ -307,7 +307,7 @@ Feature: LoanReAgingPreview | 3 | 28 | 01 March 2025 | 01 April 2025 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | | 4 | 31 | 01 April 2025 | | 0.0 | 750.0 | 0.0 | 0.0 | 0.0 | 750.0 | 0.0 | 0.0 | 0.0 | 750.0 | | 5 | 32 | 03 May 2025 | | 0.0 | 125.0 | 0.0 | 0.0 | 10.0 | 135.0 | 0.0 | 0.0 | 0.0 | 135.0 | - And Loan Repayment schedule preview has the following data in Total row: + And Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 1125.0 | 0.0 | 0.0 | 10.0 | 1135.0 | 250.0 | 0.0 | 250.0 | 885.0 | And Loan Repayment schedule has 5 periods, with the following data for periods: @@ -361,7 +361,7 @@ Feature: LoanReAgingPreview | 3 | 28 | 01 March 2025 | 01 April 2025 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | | 4 | 31 | 01 April 2025 | | 0.0 | 750.0 | 0.0 | 0.0 | 0.0 | 750.0 | 20.0 | 0.0 | 20.0 | 730.0 | | 5 | 32 | 03 May 2025 | | 0.0 | 0.0 | 0.0 | 0.0 | 20.0 | 20.0 | 0.0 | 0.0 | 0.0 | 20.0 | - Then Loan Repayment schedule preview has the following data in Total row: + Then Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 1000.0 | 0.0 | 0.0 | 20.0 | 1020.0 | 270.0 | 0.0 | 270.0 | 750.0 | And Loan Repayment schedule has 5 periods, with the following data for periods: @@ -413,7 +413,7 @@ Feature: LoanReAgingPreview | 3 | 28 | 01 March 2025 | 01 April 2025 | 900.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | | 4 | 31 | 01 April 2025 | | 0.0 | 900.0 | 0.0 | 0.0 | 0.0 | 900.0 | 0.0 | 0.0 | 0.0 | 900.0 | | 5 | 32 | 03 May 2025 | | 0.0 | 0.0 | 0.0 | 0.0 | 20.0 | 20.0 | 0.0 | 0.0 | 0.0 | 20.0 | - And Loan Repayment schedule preview has the following data in Total row: + And Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 1000.0 | 0.0 | 0.0 | 20.0 | 1020.0 | 100.0 | 0.0 | 100.0 | 920.0 | And Loan Repayment schedule has 5 periods, with the following data for periods: @@ -469,7 +469,7 @@ Feature: LoanReAgingPreview | 4 | 28 | 01 March 2025 | 01 April 2025 | 600.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | | 5 | 31 | 01 April 2025 | | 0.0 | 600.0 | 0.0 | 0.0 | 0.0 | 600.0 | 0.0 | 0.0 | 0.0 | 600.0 | | 6 | 30 | 01 May 2025 | | 0.0 | 0.0 | 0.0 | 0.0 | 20.0 | 20.0 | 0.0 | 0.0 | 0.0 | 20.0 | - Then Loan Repayment schedule preview has the following data in Total row: + Then Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 600.0 | 0.0 | 0.0 | 20.0 | 620.0 | 0.0 | 0.0 | 0.0 | 620.0 | And Loan Repayment schedule has 6 periods, with the following data for periods: @@ -547,7 +547,7 @@ Feature: LoanReAgingPreview | 7 | 30 | 01 July 2024 | | 28.34 | 14.05 | 0.25 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 | | 8 | 31 | 01 August 2024 | | 14.21 | 14.13 | 0.17 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 | | 9 | 31 | 01 September 2024| | 0.0 | 14.21 | 0.08 | 0.0 | 0.0 | 14.29 | 0.0 | 0.0 | 0.0 | 14.29 | - Then Loan Repayment schedule preview has the following data in Total row: + Then Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 100.0 | 2.8 | 0.0 | 0.0 | 102.8 | 17.01 | 0.0 | 0.0 | 85.79 | @@ -617,7 +617,7 @@ Feature: LoanReAgingPreview | 7 | 30 | 01 July 2024 | | 28.34 | 14.05 | 0.25 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 | | 8 | 31 | 01 August 2024 | | 14.21 | 14.13 | 0.17 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 | | 9 | 31 | 01 September 2024| | 0.0 | 14.21 | 0.08 | 0.0 | 0.0 | 14.29 | 0.0 | 0.0 | 0.0 | 14.29 | - Then Loan Repayment schedule preview has the following data in Total row: + Then Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 100.0 | 2.8 | 10.0 | 0.0 | 112.8 | 17.01 | 0.0 | 0.0 | 95.79 | @@ -685,7 +685,7 @@ Feature: LoanReAgingPreview | 7 | 30 | 01 July 2024 | | 28.34 | 14.05 | 0.25 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 | | 8 | 31 | 01 August 2024 | | 14.21 | 14.13 | 0.17 | 10.0 | 0.0 | 24.3 | 0.0 | 0.0 | 0.0 | 24.3 | | 9 | 31 | 01 September 2024| | 0.0 | 14.21 | 0.08 | 0.0 | 0.0 | 14.29 | 0.0 | 0.0 | 0.0 | 14.29 | - Then Loan Repayment schedule preview has the following data in Total row: + Then Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 100.0 | 2.8 | 10.0 | 0.0 | 112.8 | 17.01 | 0.0 | 0.0 | 95.79 | @@ -750,7 +750,7 @@ Feature: LoanReAgingPreview | 7 | 30 | 01 July 2024 | | 25.63 | 12.71 | 0.22 | 0.0 | 0.0 | 12.93 | 0.0 | 0.0 | 0.0 | 12.93 | | 8 | 31 | 01 August 2024 | | 12.85 | 12.78 | 0.15 | 0.0 | 0.0 | 12.93 | 0.0 | 0.0 | 0.0 | 12.93 | | 9 | 31 | 01 September 2024| | 0.0 | 12.85 | 0.07 | 0.0 | 0.0 | 12.92 | 0.0 | 0.0 | 0.0 | 12.92 | - Then Loan Repayment schedule preview has the following data in Total row: + Then Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 100.0 | 2.57 | 0.0 | 0.0 | 102.57 | 25.0 | 7.99 | 0.0 | 77.57 | @@ -821,7 +821,7 @@ Feature: LoanReAgingPreview | 8 | 30 | 01 July 2024 | | 21.25 | 10.54 | 0.19 | 0.0 | 0.0 | 10.73 | 0.0 | 0.0 | 0.0 | 10.73 | | 9 | 31 | 01 August 2024 | | 10.64 | 10.61 | 0.12 | 0.0 | 0.0 | 10.73 | 0.0 | 0.0 | 0.0 | 10.73 | | 10 | 31 | 01 September 2024 | | 0.0 | 10.64 | 0.06 | 0.0 | 0.0 | 10.7 | 0.0 | 0.0 | 0.0 | 10.7 | - Then Loan Repayment schedule preview has the following data in Total row: + Then Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 100.0 | 2.11 | 0.0 | 0.0 | 102.11 | 37.76 | 0.0 | 0.0 | 64.35 | @@ -930,7 +930,7 @@ Feature: LoanReAgingPreview | 7 | 30 | 01 July 2024 | | 28.34 | 14.05 | 0.25 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 | | 8 | 31 | 01 August 2024 | | 14.21 | 14.13 | 0.17 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 | | 9 | 31 | 01 September 2024| | 0.0 | 14.21 | 0.08 | 0.0 | 0.0 | 14.29 | 0.0 | 0.0 | 0.0 | 14.29 | - Then Loan Repayment schedule preview has the following data in Total row: + Then Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 100.0 | 2.8 | 0.0 | 0.0 | 102.8 | 17.01 | 0.0 | 0.0 | 85.79 | @@ -1158,7 +1158,7 @@ Feature: LoanReAgingPreview | 7 | 30 | 01 July 2024 | | 28.34 | 14.05 | 0.25 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 | | 8 | 31 | 01 August 2024 | | 14.21 | 14.13 | 0.17 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 | | 9 | 31 | 01 September 2024| | 0.0 | 14.21 | 0.08 | 0.0 | 0.0 | 14.29 | 0.0 | 0.0 | 0.0 | 14.29 | - Then Loan Repayment schedule preview has the following data in Total row: + Then Loan Re-Aged Repayment schedule preview has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 100.0 | 2.8 | 10.0 | 0.0 | 112.8 | 17.01 | 0.0 | 0.0 | 95.79 | diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanReAmortizationPreview.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanReAmortizationPreview.feature new file mode 100644 index 000000000..d21f5648d --- /dev/null +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanReAmortizationPreview.feature @@ -0,0 +1,389 @@ +@LoanReAmortizationPreviewFeature +Feature: LoanReAmortizationPreview + + Scenario: Verify Re-amortization preview on interest bearing loan - Interest calculation: Default Behavior - UC1 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When Admin creates a fully customized loan with the following data: + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + Then Loan Repayment schedule has 6 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + Then Loan Repayment schedule has 6 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 17.01 | 0.0 | 0.0 | 85.04 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-amortization preview by Loan external ID with the following data: + | reAmortizationInterestHandling | + | DEFAULT | + Then Loan Re-Amortization Repayment schedule preview has 6 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | 15 March 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | | 63.23 | 20.34 | 0.98 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 | + | 4 | 30 | 01 May 2024 | | 42.28 | 20.95 | 0.37 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 | + | 5 | 31 | 01 June 2024 | | 21.21 | 21.07 | 0.25 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 | + | 6 | 30 | 01 July 2024 | | 0.0 | 21.21 | 0.12 | 0.0 | 0.0 | 21.33 | 0.0 | 0.0 | 0.0 | 21.33 | + Then Loan Re-Amortization Repayment schedule preview has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.3 | 0.0 | 0.0 | 102.3 | 17.01 | 0.0 | 0.0 | 85.29 | + + When Loan Pay-off is made on "15 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + Scenario: Verify Re-amortization preview on interest bearing loan - Interest calculation: Default Behavior - Principal and interest and Fees - UC2 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When Admin creates a fully customized loan with the following data: + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + Then Loan Repayment schedule has 6 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + When Admin sets the business date to "15 February 2024" + When Admin adds "LOAN_SNOOZE_FEE" due date charge with "15 February 2024" due date and 10 EUR transaction amount + Then Loan Repayment schedule has 6 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 10.0 | 0.0 | 27.01 | 0.0 | 0.0 | 0.0 | 27.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 10.0 | 0.0 | 112.05 | 17.01 | 0.0 | 0.0 | 95.04 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + And Loan Charges tab has the following data: + | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | + | Snooze fee | false | Specified due date | 15 February 2024 | Flat | 10.0 | 0.0 | 0.0 | 10.0 | + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-amortization preview by Loan external ID with the following data: + | reAmortizationInterestHandling | + | DEFAULT | + Then Loan Re-Amortization Repayment schedule preview has 6 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 83.57 | 0.0 | 0.0 | 10.0 | 0.0 | 10.0 | 0.0 | 0.0 | 0.0 | 10.0 | + | 3 | 31 | 01 April 2024 | | 63.23 | 20.34 | 0.98 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 | + | 4 | 30 | 01 May 2024 | | 42.28 | 20.95 | 0.37 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 | + | 5 | 31 | 01 June 2024 | | 21.21 | 21.07 | 0.25 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 | + | 6 | 30 | 01 July 2024 | | 0.0 | 21.21 | 0.12 | 0.0 | 0.0 | 21.33 | 0.0 | 0.0 | 0.0 | 21.33 | + Then Loan Re-Amortization Repayment schedule preview has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.3 | 10.0 | 0.0 | 112.3 | 17.01 | 0.0 | 0.0 | 95.29 | + And Loan Charges tab has the following data: + | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | + | Snooze fee | false | Specified due date | 15 February 2024 | Flat | 10.0 | 0.0 | 0.0 | 10.0 | + + When Loan Pay-off is made on "15 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + Scenario: Verify Re-amortization preview on interest bearing loan - Interest calculation: Default Behavior - N+1 Scenario - UC3 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When Admin creates a fully customized loan with the following data: + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + Then Loan Repayment schedule has 6 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + When Admin sets the business date to "15 July 2024" + When Admin adds "LOAN_SNOOZE_FEE" due date charge with "15 July 2024" due date and 10 EUR transaction amount + Then Loan Repayment schedule has 7 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + | 7 | 14 | 15 July 2024 | | 0.0 | 0.0 | 0.0 | 10.0 | 0.0 | 10.0 | 0.0 | 0.0 | 0.0 | 10.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 10.0 | 0.0 | 112.05 | 17.01 | 0.0 | 0.0 | 95.04 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-amortization preview by Loan external ID with the following data: + | reAmortizationInterestHandling | + | DEFAULT | + Then Loan Re-Amortization Repayment schedule preview has 7 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | 15 March 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | | 63.23 | 20.34 | 0.98 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 | + | 4 | 30 | 01 May 2024 | | 42.28 | 20.95 | 0.37 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 | + | 5 | 31 | 01 June 2024 | | 21.21 | 21.07 | 0.25 | 0.0 | 0.0 | 21.32 | 0.0 | 0.0 | 0.0 | 21.32 | + | 6 | 30 | 01 July 2024 | | 0.0 | 21.21 | 0.12 | 0.0 | 0.0 | 21.33 | 0.0 | 0.0 | 0.0 | 21.33 | + | 7 | 14 | 15 July 2024 | | 0.0 | 0.0 | 0.0 | 10.0 | 0.0 | 10.0 | 0.0 | 0.0 | 0.0 | 10.0 | + Then Loan Re-Amortization Repayment schedule preview has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.3 | 10.0 | 0.0 | 112.3 | 17.01 | 0.0 | 0.0 | 95.29 | + + When Loan Pay-off is made on "15 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + Scenario: Verify Re-amortization preview on interest bearing loan - Interest calculation: Default Behavior - Charge-back before re-aging - UC4 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When Admin creates a fully customized loan with the following data: + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALC_EMI_360_30_CHARGEBACK_INTEREST_PENALTY_FEE_PRINCIPAL | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + Then Loan Repayment schedule has 6 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + When Admin makes "REPAYMENT_ADJUSTMENT_CHARGEBACK" chargeback with 17.01 EUR transaction amount + Then Loan Repayment schedule has 6 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.14 | 32.86 | 1.16 | 0.0 | 0.0 | 34.02 | 0.0 | 0.0 | 0.0 | 34.02 | + | 3 | 31 | 01 April 2024 | | 50.52 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.8 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.99 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.99 | 0.1 | 0.0 | 0.0 | 17.09 | 0.0 | 0.0 | 0.0 | 17.09 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 116.43 | 2.72 | 0.0 | 0.0 | 119.15 | 17.01 | 0.0 | 0.0 | 102.14 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | + | 01 February 2024 | Chargeback | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 100.0 | false | + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-amortization preview by Loan external ID with the following data: + | reAmortizationInterestHandling | + | DEFAULT | + Then Loan Re-Amortization Repayment schedule preview has 6 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | 15 March 2024 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | | 76.08 | 23.92 | 1.74 | 0.0 | 0.0 | 25.66 | 0.0 | 0.0 | 0.0 | 25.66 | + | 4 | 30 | 01 May 2024 | | 50.86 | 25.22 | 0.44 | 0.0 | 0.0 | 25.66 | 0.0 | 0.0 | 0.0 | 25.66 | + | 5 | 31 | 01 June 2024 | | 25.5 | 25.36 | 0.3 | 0.0 | 0.0 | 25.66 | 0.0 | 0.0 | 0.0 | 25.66 | + | 6 | 30 | 01 July 2024 | | 0.0 | 25.5 | 0.15 | 0.0 | 0.0 | 25.65 | 0.0 | 0.0 | 0.0 | 25.65 | + Then Loan Re-Amortization Repayment schedule preview has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 116.43 | 3.21 | 0.0 | 0.0 | 119.64 | 17.01 | 0.0 | 0.0 | 102.63 | + + When Loan Pay-off is made on "15 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + Scenario: Verify Re-amortization preview on interest bearing loan - Interest calculation: Default Behavior - Partially paid installment - UC5 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When Admin set "LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL" loan product "DEFAULT" transaction type to "NEXT_INSTALLMENT" future installment allocation rule + When Admin creates a fully customized loan with the following data: + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + Then Loan Repayment schedule has 6 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 20.0 EUR transaction amount + Then Loan Repayment schedule has 6 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.03 | 16.54 | 0.47 | 0.0 | 0.0 | 17.01 | 2.99 | 2.99 | 0.0 | 14.02 | + | 3 | 31 | 01 April 2024 | | 50.41 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.69 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.88 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.88 | 0.1 | 0.0 | 0.0 | 16.98 | 0.0 | 0.0 | 0.0 | 16.98 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.03 | 0.0 | 0.0 | 102.03 | 20.0 | 2.99 | 0.0 | 82.03 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + | 01 February 2024 | Repayment | 20.0 | 19.42 | 0.58 | 0.0 | 0.0 | 80.58 | false | + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-amortization preview by Loan external ID with the following data: + | reAmortizationInterestHandling | + | DEFAULT | + Then Loan Re-Amortization Repayment schedule preview has 6 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | 15 March 2024 | 80.58 | 2.99 | 0.0 | 0.0 | 0.0 | 2.99 | 2.99 | 2.99 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | | 60.96 | 19.62 | 0.94 | 0.0 | 0.0 | 20.56 | 0.0 | 0.0 | 0.0 | 20.56 | + | 4 | 30 | 01 May 2024 | | 40.76 | 20.2 | 0.36 | 0.0 | 0.0 | 20.56 | 0.0 | 0.0 | 0.0 | 20.56 | + | 5 | 31 | 01 June 2024 | | 20.44 | 20.32 | 0.24 | 0.0 | 0.0 | 20.56 | 0.0 | 0.0 | 0.0 | 20.56 | + | 6 | 30 | 01 July 2024 | | 0.0 | 20.44 | 0.12 | 0.0 | 0.0 | 20.56 | 0.0 | 0.0 | 0.0 | 20.56 | + Then Loan Re-Amortization Repayment schedule preview has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.24 | 0.0 | 0.0 | 102.24 | 20.0 | 2.99 | 0.0 | 82.24 | + + When Loan Pay-off is made on "15 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + Scenario: Verify Re-amortization preview on interest bearing loan - Interest calculation: Default Behavior - DownPayment Scenarios - UC6 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When Admin set "LP2_ADV_PYMNT_INTEREST_RECALCULATION_DAILY_EMI_360_30_MULTIDISBURSE_AUTO_DOWNPAYMENT" loan product "DEFAULT" transaction type to "NEXT_INSTALLMENT" future installment allocation rule + When Admin creates a fully customized loan with the following data: + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP2_ADV_PYMNT_INTEREST_RECALCULATION_DAILY_EMI_360_30_MULTIDISBURSE_AUTO_DOWNPAYMENT | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + Then Loan Repayment schedule has 7 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2024 | 01 January 2024 | 75.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | + | 2 | 31 | 01 February 2024 | | 62.68 | 12.32 | 0.44 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 3 | 29 | 01 March 2024 | | 50.29 | 12.39 | 0.37 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 4 | 31 | 01 April 2024 | | 37.82 | 12.47 | 0.29 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 5 | 30 | 01 May 2024 | | 25.28 | 12.54 | 0.22 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 6 | 31 | 01 June 2024 | | 12.67 | 12.61 | 0.15 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 7 | 30 | 01 July 2024 | | 0.0 | 12.67 | 0.07 | 0.0 | 0.0 | 12.74 | 0.0 | 0.0 | 0.0 | 12.74 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.54 | 0.0 | 0.0 | 101.54 | 25.0 | 0.0 | 0.0 | 76.54 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 January 2024 | Down Payment | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | 75.0 | false | false | + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 12.76 EUR transaction amount + Then Loan Repayment schedule has 7 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2024 | 01 January 2024 | 75.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | + | 2 | 31 | 01 February 2024| 01 February 2024 | 62.68 | 12.32 | 0.44 | 0.0 | 0.0 | 12.76 | 12.76 | 0.0 | 0.0 | 0.0 | + | 3 | 29 | 01 March 2024 | | 50.29 | 12.39 | 0.37 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 4 | 31 | 01 April 2024 | | 37.82 | 12.47 | 0.29 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 5 | 30 | 01 May 2024 | | 25.28 | 12.54 | 0.22 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 6 | 31 | 01 June 2024 | | 12.67 | 12.61 | 0.15 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 7 | 30 | 01 July 2024 | | 0.0 | 12.67 | 0.07 | 0.0 | 0.0 | 12.74 | 0.0 | 0.0 | 0.0 | 12.74 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.54 | 0.0 | 0.0 | 101.54 | 37.76 | 0.0 | 0.0 | 63.78 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 January 2024 | Down Payment | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | 75.0 | false | false | + | 01 February 2024 | Repayment | 12.76 | 12.32 | 0.44 | 0.0 | 0.0 | 62.68 | false | false | + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-amortization preview by Loan external ID with the following data: + | reAmortizationInterestHandling | + | DEFAULT | + Then Loan Re-Amortization Repayment schedule preview has 7 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2024 | 01 January 2024 | 75.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | + | 2 | 31 | 01 February 2024 | 01 February 2024 | 62.68 | 12.32 | 0.44 | 0.0 | 0.0 | 12.76 | 12.76 | 0.0 | 0.0 | 0.0 | + | 3 | 29 | 01 March 2024 | 15 March 2024 | 62.68 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 4 | 31 | 01 April 2024 | | 47.43 | 15.25 | 0.74 | 0.0 | 0.0 | 15.99 | 0.0 | 0.0 | 0.0 | 15.99 | + | 5 | 30 | 01 May 2024 | | 31.72 | 15.71 | 0.28 | 0.0 | 0.0 | 15.99 | 0.0 | 0.0 | 0.0 | 15.99 | + | 6 | 31 | 01 June 2024 | | 15.92 | 15.8 | 0.19 | 0.0 | 0.0 | 15.99 | 0.0 | 0.0 | 0.0 | 15.99 | + | 7 | 30 | 01 July 2024 | | 0.0 | 15.92 | 0.09 | 0.0 | 0.0 | 16.01 | 0.0 | 0.0 | 0.0 | 16.01 | + Then Loan Re-Amortization Repayment schedule preview has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.74 | 0.0 | 0.0 | 101.74 | 37.76 | 0.0 | 0.0 | 63.98 | + + When Loan Pay-off is made on "15 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java index bc4a4bc18..9c5096171 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java @@ -66,6 +66,7 @@ import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.ExternalIdFactory; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.loanaccount.api.request.ReAgePreviewRequest; +import org.apache.fineract.portfolio.loanaccount.api.request.ReAmortizationPreviewRequest; import org.apache.fineract.portfolio.loanaccount.data.LoanRepaymentScheduleInstallmentData; import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType; @@ -76,6 +77,7 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleD import org.apache.fineract.portfolio.loanaccount.service.LoanChargePaidByReadService; import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService; import org.apache.fineract.portfolio.loanaccount.service.reaging.LoanReAgingService; +import org.apache.fineract.portfolio.loanaccount.service.reamortization.LoanReAmortizationService; import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData; import org.apache.fineract.portfolio.paymenttype.service.PaymentTypeReadPlatformService; import org.springframework.data.domain.Page; @@ -111,6 +113,7 @@ public class LoanTransactionsApiResource { private final PaymentTypeReadPlatformService paymentTypeReadPlatformService; private final LoanChargePaidByReadService loanChargePaidByReadService; private final LoanReAgingService loanReAgingService; + private final LoanReAmortizationService loanReAmortizationService; @GET @Path("{loanId}/transactions/template") @@ -806,4 +809,26 @@ public class LoanTransactionsApiResource { return loanReAgingService.previewReAge(null, loanExternalId, reAgePreviewRequest); } + @GET + @Path("{loanId}/transactions/reamortized-preview") + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Preview Re-Amortized Schedule", description = "Generates a preview of the re-amortized loan schedule based on the provided parameters without creating any transactions or modifying the loan.") + public LoanScheduleData previewReAmortizationSchedule( + @PathParam("loanId") @Parameter(description = "loanId", required = true) final Long loanId, + @Valid @BeanParam final ReAmortizationPreviewRequest reAmortizationPreviewRequest) { + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); + return loanReAmortizationService.previewReAmortization(loanId, null, reAmortizationPreviewRequest); + } + + @GET + @Path("external-id/{loanExternalId}/transactions/reamortized-preview") + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Preview Re-amortized Schedule", description = "Generates a preview of the re-amortized loan schedule based on the provided parameters without creating any transactions or modifying the loan.") + public LoanScheduleData previewReAmortizationSchedule( + @PathParam("loanExternalId") @Parameter(description = "loanExternalId", required = true) final String loanExternalId, + @Valid @BeanParam final ReAmortizationPreviewRequest reAmortizationPreviewRequest) { + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); + return loanReAmortizationService.previewReAmortization(null, loanExternalId, reAmortizationPreviewRequest); + } + } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/request/ReAmortizationPreviewRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/request/ReAmortizationPreviewRequest.java new file mode 100644 index 000000000..c97577f9c --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/request/ReAmortizationPreviewRequest.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.loanaccount.api.request; + +import io.swagger.v3.oas.annotations.Parameter; +import jakarta.validation.constraints.NotBlank; +import jakarta.ws.rs.QueryParam; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.fineract.portfolio.loanaccount.domain.reamortization.LoanReAmortizationInterestHandlingType; +import org.apache.fineract.validation.constraints.EnumValue; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ReAmortizationPreviewRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @QueryParam("reAmortizationInterestHandling") + @Parameter(description = "The interest handling type (DEFAULT, WAIVE_INTEREST, EQUAL_AMORTIZATION_INTEREST_SPLIT)", required = true) + @NotBlank(message = "{org.apache.fineract.reamortization.interest-handling-type.not-blank}") + @EnumValue(enumClass = LoanReAmortizationInterestHandlingType.class, message = "{org.apache.fineract.interest-handling-type.invalid}") + private String reAmortizationInterestHandling; + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationService.java index e405ec119..5a656a3af 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationService.java @@ -22,10 +22,12 @@ import static java.math.BigDecimal.ZERO; import java.math.BigDecimal; import java.time.LocalDate; +import java.util.Collection; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.apache.fineract.infrastructure.codes.domain.CodeValue; import org.apache.fineract.infrastructure.codes.domain.CodeValueRepository; @@ -40,17 +42,27 @@ import org.apache.fineract.infrastructure.event.business.domain.loan.reamortizat import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.reamortization.LoanReAmortizeTransactionBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.reamortization.LoanUndoReAmortizeTransactionBusinessEvent; import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; +import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.monetary.domain.Money; import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants; import org.apache.fineract.portfolio.loanaccount.api.LoanReAmortizationApiConstants; +import org.apache.fineract.portfolio.loanaccount.api.request.ReAmortizationPreviewRequest; +import org.apache.fineract.portfolio.loanaccount.data.DisbursementData; +import org.apache.fineract.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData; import org.apache.fineract.portfolio.loanaccount.domain.Loan; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; +import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepaymentPeriodData; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType; import org.apache.fineract.portfolio.loanaccount.domain.reamortization.LoanReAmortizationInterestHandlingType; import org.apache.fineract.portfolio.loanaccount.domain.reamortization.LoanReAmortizationParameter; +import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData; +import org.apache.fineract.portfolio.loanaccount.repository.LoanCapitalizedIncomeBalanceRepository; import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator; import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler; +import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService; +import org.apache.fineract.portfolio.loanaccount.service.LoanRepaymentScheduleService; import org.apache.fineract.portfolio.loanaccount.service.LoanScheduleService; import org.apache.fineract.portfolio.loanaccount.service.ReprocessLoanTransactionsService; import org.springframework.stereotype.Service; @@ -70,6 +82,9 @@ public class LoanReAmortizationService { private final ReprocessLoanTransactionsService reprocessLoanTransactionsService; private final CodeValueRepository codeValueRepository; private final LoanScheduleService loanScheduleService; + private final LoanRepaymentScheduleService loanRepaymentScheduleService; + private final LoanReadPlatformService loanReadPlatformService; + private final LoanCapitalizedIncomeBalanceRepository loanCapitalizedIncomeBalanceRepository; public CommandProcessingResult reAmortize(final Long loanId, final JsonCommand command) { final Loan loan = loanAssembler.assembleFrom(loanId); @@ -77,7 +92,7 @@ public class LoanReAmortizationService { final LoanTransaction reAmortizeTransaction = createReAmortizeTransaction(loan, command); reAmortizeTransaction.setLoanReAmortizationParameter(createReAmortizationParameter(reAmortizeTransaction, command)); - processReAmortizationTransaction(loan, reAmortizeTransaction); + processReAmortizationTransaction(loan, reAmortizeTransaction, true); loanTransactionRepository.saveAndFlush(reAmortizeTransaction); final Map changes = new LinkedHashMap<>(); @@ -130,6 +145,36 @@ public class LoanReAmortizationService { .with(changes).build(); } + @Transactional(readOnly = true) + public LoanScheduleData previewReAmortization(final Long loanId, final String loanExternalId, + final ReAmortizationPreviewRequest reAmortizationPreviewRequest) { + final Loan loan = loanId != null ? loanAssembler.assembleFrom(loanId) + : loanAssembler.assembleFrom(ExternalIdFactory.produce(loanExternalId), false); + return previewReAmortization(loan, reAmortizationPreviewRequest); + } + + private LoanScheduleData previewReAmortization(final Loan loan, final ReAmortizationPreviewRequest reAmortizationPreviewRequest) { + reAmortizationValidator.validateReAmortize(loan); + + final LoanTransaction reAmortizeTransaction = createReAmortizeTransactionFromPreviewRequest(loan, reAmortizationPreviewRequest); + processReAmortizationTransaction(loan, reAmortizeTransaction, false); + loan.updateLoanScheduleDependentDerivedFields(); + + final CurrencyData currencyData = new CurrencyData(loan.getCurrencyCode(), null, loan.getCurrency().getDigitsAfterDecimal(), + loan.getCurrency().getInMultiplesOf(), null, null); + final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData = new RepaymentScheduleRelatedLoanData( + loan.getDisbursementDate(), loan.getDisbursementDate(), currencyData, loan.getPrincipal().getAmount(), + loan.getInArrearsTolerance().getAmount(), ZERO); + final Collection disbursementData = loanReadPlatformService.retrieveLoanDisbursementDetails(loan.getId()); + final Collection capitalizedIncomeData = loanCapitalizedIncomeBalanceRepository + .findRepaymentPeriodDataByLoanId(loan.getId()); + final List sortedInstallments = loan.getRepaymentScheduleInstallments().stream() + .sorted(Comparator.comparingInt(LoanRepaymentScheduleInstallment::getInstallmentNumber)).collect(Collectors.toList()); + + return loanRepaymentScheduleService.extractLoanScheduleData(sortedInstallments, repaymentScheduleRelatedLoanData, disbursementData, + capitalizedIncomeData, loan.isInterestRecalculationEnabled(), loan.getLoanProductRelatedDetail().getLoanScheduleType()); + } + private void reverseReAmortizeTransaction(LoanTransaction reAmortizeTransaction, JsonCommand command) { ExternalId reversalExternalId = externalIdFactory.createFromCommand(command, LoanReAmortizationApiConstants.externalIdParameterName); @@ -163,6 +208,23 @@ public class LoanReAmortizationService { txPrincipalAmount, ZERO, ZERO, ZERO, null, false, null, txExternalId); } + private LoanTransaction createReAmortizeTransactionFromPreviewRequest(final Loan loan, + final ReAmortizationPreviewRequest reAmortizationPreviewRequest) { + // re-amortization transaction date is always the current business date + final LocalDate transactionDate = DateUtils.getBusinessLocalDate(); + final Money txPrincipal = loan.getTotalPrincipalOutstandingUntil(transactionDate); + final BigDecimal txPrincipalAmount = txPrincipal.getAmount(); + + final LoanTransaction reAmortizationTransaction = new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.REAMORTIZE, + transactionDate, txPrincipalAmount, txPrincipalAmount, ZERO, ZERO, ZERO, null, false, null, null); + + final LoanReAmortizationParameter reAmortizationParameter = createReAmortizationParameterFromPreviewRequest( + reAmortizationTransaction, reAmortizationPreviewRequest); + reAmortizationTransaction.setLoanReAmortizationParameter(reAmortizationParameter); + + return reAmortizationTransaction; + } + private LoanReAmortizationParameter createReAmortizationParameter(LoanTransaction reAmortizationTransaction, JsonCommand command) { LoanReAmortizationInterestHandlingType reAmortizationInterestHandlingType = command.enumValueOfParameterNamed( LoanReAmortizationApiConstants.reAmortizationInterestHandlingParamName, LoanReAmortizationInterestHandlingType.class); @@ -179,10 +241,22 @@ public class LoanReAmortizationService { return new LoanReAmortizationParameter(reAmortizationTransaction, reAmortizationInterestHandlingType, reasonCodeValue); } - private void processReAmortizationTransaction(final Loan loan, final LoanTransaction reAmortizationTransaction) { + private LoanReAmortizationParameter createReAmortizationParameterFromPreviewRequest(final LoanTransaction reAmortizationTransaction, + final ReAmortizationPreviewRequest reAmortizationPreviewRequest) { + final LoanReAmortizationInterestHandlingType reAmortizationInterestHandlingType = LoanReAmortizationInterestHandlingType + .valueOf(reAmortizationPreviewRequest.getReAmortizationInterestHandling()); + return new LoanReAmortizationParameter(reAmortizationTransaction, reAmortizationInterestHandlingType, null); + } + + private void processReAmortizationTransaction(final Loan loan, final LoanTransaction reAmortizationTransaction, + final boolean withPostTransactionChecks) { if (loan.isInterestBearingAndInterestRecalculationEnabled()) { loanScheduleService.regenerateRepaymentSchedule(loan); - reprocessLoanTransactionsService.reprocessTransactions(loan, List.of(reAmortizationTransaction)); + if (withPostTransactionChecks) { + reprocessLoanTransactionsService.reprocessTransactions(loan, List.of(reAmortizationTransaction)); + } else { + reprocessLoanTransactionsService.reprocessTransactionsWithoutChecks(loan, List.of(reAmortizationTransaction)); + } } else { reprocessLoanTransactionsService.processLatestTransaction(reAmortizationTransaction, loan); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidator.java index 3e4888908..511146d14 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidator.java @@ -54,6 +54,10 @@ public class LoanReAmortizationValidator { validateReAmortizeBusinessRules(loan); } + public void validateReAmortize(final Loan loan) { + validateReAmortizeBusinessRules(loan); + } + private void validateReAmortizeRequest(JsonCommand command) { List dataValidationErrors = new ArrayList<>(); DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.reAmortization");