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 ff24d6a0eb1..b6fe3222786 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 @@ -20,19 +20,29 @@ 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.stream.Collectors; import lombok.extern.slf4j.Slf4j; import okhttp3.ResponseBody; +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.client.services.LoanTransactionsApi; import org.apache.fineract.test.factory.LoanRequestFactory; import org.apache.fineract.test.helper.ErrorHelper; +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.LoanReAgeEvent; import org.apache.fineract.test.stepdef.AbstractStepDef; @@ -44,6 +54,9 @@ @Slf4j public class LoanReAgingStepDef extends AbstractStepDef { + private static final String DATE_FORMAT = "dd MMMM yyyy"; + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern(DATE_FORMAT); + @Autowired private LoanTransactionsApi loanTransactionsApi; @@ -146,4 +159,197 @@ public void adminFailsToCreateReAgingTransactionWithError(final String expectedE ErrorHelper.checkFailedApiCall(response, 403); } + @When("Admin creates a Loan re-aging preview with the following data:") + public void createReAgingPreview(DataTable table) throws IOException { + Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); + long loanId = loanResponse.body().getLoanId(); + + List data = table.asLists().get(1); + int frequencyNumber = Integer.parseInt(data.get(0)); + String frequencyType = data.get(1); + String startDate = data.get(2); + int numberOfInstallments = Integer.parseInt(data.get(3)); + + PostLoansLoanIdTransactionsRequest reAgingRequest = LoanRequestFactory// + .defaultReAgingRequest()// + .frequencyNumber(frequencyNumber)// + .frequencyType(frequencyType)// + .startDate(startDate)// + .numberOfInstallments(numberOfInstallments);// + + Response response = loanTransactionsApi.previewReAgeSchedule(loanId, reAgingRequest).execute(); + ErrorHelper.checkSuccessfulApiCall(response); + testContext().set(TestContextKey.LOAN_REAGING_PREVIEW_RESPONSE, response); + + log.info( + "Re-aging preview created for loan ID: {} with parameters: frequencyNumber={}, frequencyType={}, startDate={}, numberOfInstallments={}", + loanId, frequencyNumber, frequencyType, startDate, numberOfInstallments); + } + + @When("Admin creates a Loan re-aging preview by Loan external ID with the following data:") + public void createReAgingPreviewByLoanExternalId(DataTable table) throws IOException { + Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); + String loanExternalId = loanResponse.body().getResourceExternalId(); + + List data = table.asLists().get(1); + int frequencyNumber = Integer.parseInt(data.get(0)); + String frequencyType = data.get(1); + String startDate = data.get(2); + int numberOfInstallments = Integer.parseInt(data.get(3)); + + PostLoansLoanIdTransactionsRequest reAgingRequest = LoanRequestFactory// + .defaultReAgingRequest()// + .frequencyNumber(frequencyNumber)// + .frequencyType(frequencyType)// + .startDate(startDate)// + .numberOfInstallments(numberOfInstallments);// + + Response response = loanTransactionsApi.previewReAgeSchedule1(loanExternalId, reAgingRequest).execute(); + ErrorHelper.checkSuccessfulApiCall(response); + testContext().set(TestContextKey.LOAN_REAGING_PREVIEW_RESPONSE, response); + + log.info( + "Re-aging preview created for loan external ID: {} with parameters: frequencyNumber={}, frequencyType={}, startDate={}, numberOfInstallments={}", + loanExternalId, frequencyNumber, frequencyType, startDate, numberOfInstallments); + } + + @Then("Loan Repayment schedule preview has {int} periods, with the following data for periods:") + public void loanRepaymentSchedulePreviewPeriodsCheck(int linesExpected, DataTable table) { + Response scheduleResponse = testContext().get(TestContextKey.LOAN_REAGING_PREVIEW_RESPONSE); + + List repaymentPeriods = scheduleResponse.body().getPeriods(); + + Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); + String resourceId = String.valueOf(loanResponse.body().getLoanId()); + + List> data = table.asLists(); + int nrLines = data.size(); + 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); + } + } + + @Then("Loan Repayment schedule preview has the following data in Total row:") + public void loanRepaymentScheduleAmountCheck(DataTable table) { + List> data = table.asLists(); + List header = data.get(0); + List expectedValues = data.get(1); + Response scheduleResponse = testContext().get(TestContextKey.LOAN_REAGING_PREVIEW_RESPONSE); + validateRepaymentScheduleTotal(header, scheduleResponse.body(), expectedValues); + } + + private List fetchValuesOfRepaymentSchedule(List header, LoanSchedulePeriodData repaymentPeriod) { + 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; + } + + @SuppressFBWarnings("SF_SWITCH_NO_DEFAULT") + private List validateRepaymentScheduleTotal(List header, LoanScheduleData repaymentSchedule, + List expectedAmounts) { + List actualValues = new ArrayList<>(); + Double paidActual = 0.0; + List periods = repaymentSchedule.getPeriods(); + for (LoanSchedulePeriodData period : periods) { + if (null != period.getTotalPaidForPeriod()) { + paidActual += period.getTotalPaidForPeriod().doubleValue(); + } + } + BigDecimal paidActualBd = new BigDecimal(paidActual).setScale(2, RoundingMode.HALF_DOWN); + + for (int i = 0; i < header.size(); i++) { + String headerName = header.get(i); + String expectedValue = expectedAmounts.get(i); + switch (headerName) { + case "Principal due" -> assertThat(repaymentSchedule.getTotalPrincipalExpected().doubleValue())// + .as(ErrorMessageHelper.wrongAmountInRepaymentSchedulePrincipal( + repaymentSchedule.getTotalPrincipalExpected().doubleValue(), Double.valueOf(expectedValue)))// + .isEqualTo(Double.valueOf(expectedValue));// + case "Interest" -> assertThat(repaymentSchedule.getTotalInterestCharged().doubleValue())// + .as(ErrorMessageHelper.wrongAmountInRepaymentScheduleInterest( + repaymentSchedule.getTotalInterestCharged().doubleValue(), Double.valueOf(expectedValue)))// + .isEqualTo(Double.valueOf(expectedValue));// + case "Fees" -> assertThat(repaymentSchedule.getTotalFeeChargesCharged().doubleValue())// + .as(ErrorMessageHelper.wrongAmountInRepaymentScheduleFees( + repaymentSchedule.getTotalFeeChargesCharged().doubleValue(), Double.valueOf(expectedValue)))// + .isEqualTo(Double.valueOf(expectedValue));// + case "Penalties" -> assertThat(repaymentSchedule.getTotalPenaltyChargesCharged().doubleValue())// + .as(ErrorMessageHelper.wrongAmountInRepaymentSchedulePenalties( + repaymentSchedule.getTotalPenaltyChargesCharged().doubleValue(), Double.valueOf(expectedValue)))// + .isEqualTo(Double.valueOf(expectedValue));// + case "Due" -> assertThat(repaymentSchedule.getTotalRepaymentExpected().doubleValue())// + .as(ErrorMessageHelper.wrongAmountInRepaymentScheduleDue( + repaymentSchedule.getTotalRepaymentExpected().doubleValue(), Double.valueOf(expectedValue)))// + .isEqualTo(Double.valueOf(expectedValue));// + case "Paid" -> assertThat(paidActualBd.doubleValue())// + .as(ErrorMessageHelper.wrongAmountInRepaymentSchedulePaid(paidActualBd.doubleValue(), + Double.valueOf(expectedValue)))// + .isEqualTo(Double.valueOf(expectedValue));// + case "In advance" -> assertThat(repaymentSchedule.getTotalPaidInAdvance().doubleValue())// + .as(ErrorMessageHelper.wrongAmountInRepaymentScheduleInAdvance( + repaymentSchedule.getTotalPaidInAdvance().doubleValue(), Double.valueOf(expectedValue)))// + .isEqualTo(Double.valueOf(expectedValue));// + case "Late" -> assertThat(repaymentSchedule.getTotalPaidLate().doubleValue())// + .as(ErrorMessageHelper.wrongAmountInRepaymentScheduleLate(repaymentSchedule.getTotalPaidLate().doubleValue(), + Double.valueOf(expectedValue)))// + .isEqualTo(Double.valueOf(expectedValue));// + case "Waived" -> assertThat(repaymentSchedule.getTotalWaived().doubleValue())// + .as(ErrorMessageHelper.wrongAmountInRepaymentScheduleWaived(repaymentSchedule.getTotalWaived().doubleValue(), + Double.valueOf(expectedValue)))// + .isEqualTo(Double.valueOf(expectedValue));// + case "Outstanding" -> assertThat(repaymentSchedule.getTotalOutstanding().doubleValue())// + .as(ErrorMessageHelper.wrongAmountInRepaymentScheduleOutstanding( + repaymentSchedule.getTotalOutstanding().doubleValue(), Double.valueOf(expectedValue)))// + .isEqualTo(Double.valueOf(expectedValue));// + } + } + 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 37c72d2d345..f23da39a413 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 @@ -48,6 +48,7 @@ public abstract class TestContextKey { public static final String LOAN_REFUND_RESPONSE = "loanRefundResponse"; public static final String LOAN_REAGING_RESPONSE = "loanReAgingResponse"; 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_UNDO_RESPONSE = "loanReAmortizationUndoResponse"; public static final String BUSINESS_DATE_RESPONSE = "businessDateResponse"; diff --git a/fineract-e2e-tests-runner/src/test/resources/features/Loan.feature b/fineract-e2e-tests-runner/src/test/resources/features/Loan.feature index 9a356d264fa..ac137db098a 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/Loan.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/Loan.feature @@ -7818,8 +7818,8 @@ Feature: Loan | 01 January 2025 | 01 January 2025 | 700.0 | | | 01 January 2025 | 01 January 2025 | 200.0 | | - When Loan Pay-off is made on "1 January 2025" - Then Loan's all installments have obligations met + When Loan Pay-off is made on "01 January 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C4029 Scenario: Verify tranche interest bearing progressive loan that expects two tranches at the same date with over expected disb amount in expected order - UC2 @@ -7892,7 +7892,7 @@ Feature: Loan | 01 January 2025 | 01 January 2025 | 250.0 | | When Loan Pay-off is made on "1 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C4030 Scenario: Verify tranche interest bearing progressive loan that expects two tranches at the same date with over expected disb amount in not expected order - UC3 @@ -7966,6 +7966,9 @@ Feature: Loan | 01 January 2025 | 01 January 2025 | 300.0 | | | 01 January 2025 | 01 January 2025 | 600.0 | | + When Loan Pay-off is made on "01 January 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4031 Scenario: Verify tranche interest bearing progressive loan that expects two tranches at the same date with diff expected disb amounts in diff order - UC4 When Admin sets the business date to "01 January 2025" @@ -8038,7 +8041,7 @@ Feature: Loan | 01 January 2025 | 01 January 2025 | 300.0 | | When Loan Pay-off is made on "1 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C4032 Scenario: Verify tranche interest bearing progressive loan that expects two tranches at the same date in defined order with over expected 2nd disb amount - UC5 @@ -8111,7 +8114,7 @@ Feature: Loan | 01 January 2025 | 01 January 2025 | 800.0 | | When Loan Pay-off is made on "1 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C4033 Scenario: Verify tranche interest bearing progressive loan that expects tranche with added 2nd tranche at the same date and undo disbursement - UC6 @@ -8246,7 +8249,7 @@ Feature: Loan Then Admin fails to disburse the loan on "01 February 2025" with "50" amount When Loan Pay-off is made on "1 February 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C4034 Scenario: Verify tranche interest bearing progressive loan that expects tranches at the same date with repayment and undo last disbursement - UC7 @@ -8357,7 +8360,7 @@ Feature: Loan Then Admin fails to disburse the loan on "01 January 2025" with "200" amount When Loan Pay-off is made on "1 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C4035 Scenario: Verify tranche interest bearing progressive loan that expects tranche with added 2 tranches at the same date - UC8 @@ -8485,7 +8488,7 @@ Feature: Loan Then Admin fails to disburse the loan on "01 February 2025" with "50" amount When Loan Pay-off is made on "1 February 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C4118 Scenario: Verify cumulative multidisb loan with 2nd disb at 1st installment with flat interest type and same_as_repeyment interest calculation period - UC1 diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanAccrualActivity.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanAccrualActivity.feature index 4d74b356e5d..d5ae72585ce 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanAccrualActivity.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanAccrualActivity.feature @@ -5816,8 +5816,7 @@ Feature: LoanAccrualActivity When Admin sets the business date to "28 March 2025" And Admin runs inline COB job for Loan When Admin makes Credit Balance Refund transaction on "28 March 2025" with 100 EUR transaction amount - Then Loan status will be "CLOSED_OBLIGATIONS_MET" - Then Loan has 0 outstanding amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met Then Loan Repayment schedule has 13 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 | | | | 21 March 2025 | | 242.46 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -5890,6 +5889,9 @@ Feature: LoanAccrualActivity | 19 April 2025 | Accrual | 0.08 | 0.0 | 0.08 | 0.0 | 0.0 | 0.0 | false | false | | 20 April 2025 | Accrual | 0.08 | 0.0 | 0.08 | 0.0 | 0.0 | 0.0 | false | false | + When Loan Pay-off is made on "21 April 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3693 Scenario: Verify that accruals are added in case of reversed repayment made before MIR and CBR for progressive loan with auto downpayment - UC2 When Admin sets the business date to "21 March 2025" @@ -6031,6 +6033,9 @@ Feature: LoanAccrualActivity | 19 April 2025 | Accrual | 0.08 | 0.0 | 0.08 | 0.0 | 0.0 | 0.0 | false | false | | 20 April 2025 | Accrual | 0.08 | 0.0 | 0.08 | 0.0 | 0.0 | 0.0 | false | false | + When Loan Pay-off is made on "21 April 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3694 Scenario: Verify repayment and accruals are added after reversed repayment made before MIR and CBR for progressive loan - UC3 When Admin sets the business date to "21 March 2025" @@ -6226,6 +6231,9 @@ Feature: LoanAccrualActivity | 21 April 2025 | Repayment | 80.0 | 40.0 | 0.77 | 0.0 | 0.0 | 0.0 | true | false | | 21 April 2025 | Accrual | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | false | + When Loan Pay-off is made on "21 April 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3695 Scenario: Verify accrual activity of overpaid loan in case of reversed repayment made before MIR and CBR for loan with interest refund - UC4 When Admin sets the business date to "21 March 2025" @@ -6286,8 +6294,7 @@ Feature: LoanAccrualActivity When Admin sets the business date to "28 March 2025" And Admin runs inline COB job for Loan When Admin makes Credit Balance Refund transaction on "28 March 2025" with 100 EUR transaction amount - Then Loan status will be "CLOSED_OBLIGATIONS_MET" - Then Loan has 0 outstanding amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met When Admin sets the business date to "02 April 2025" And Admin runs inline COB job for Loan When Customer undo "1"th "Merchant Issued Refund" transaction made on "21 March 2025" @@ -6353,8 +6360,7 @@ Feature: LoanAccrualActivity When Admin sets the business date to "23 April 2025" And Admin runs inline COB job for Loan When Admin makes Credit Balance Refund transaction on "23 April 2025" with 156.7 EUR transaction amount - Then Loan status will be "CLOSED_OBLIGATIONS_MET" - Then Loan has 0 outstanding amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met Then Loan Repayment schedule has 12 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 | | | | 21 March 2025 | | 242.46 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -6422,6 +6428,9 @@ Feature: LoanAccrualActivity # - CBR on active loan - with outstanding amount is forbidden -# Then Credit Balance Refund transaction on active loan "25 April 2025" with 100 EUR transaction amount will result an error + When Loan Pay-off is made on "25 April 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3696 Scenario: Verify accrual activity of overpaid loan in case of reversed repayment made before MIR and CBR for progressive multidisbursal loan - UC5 When Admin sets the business date to "21 March 2025" @@ -6482,8 +6491,7 @@ Feature: LoanAccrualActivity When Admin sets the business date to "28 March 2025" And Admin runs inline COB job for Loan When Admin makes Credit Balance Refund transaction on "28 March 2025" with 100 EUR transaction amount - Then Loan status will be "CLOSED_OBLIGATIONS_MET" - Then Loan has 0 outstanding amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met When Admin sets the business date to "02 April 2025" And Admin runs inline COB job for Loan When Customer undo "1"th "Repayment" transaction made on "21 March 2025" @@ -6550,8 +6558,7 @@ Feature: LoanAccrualActivity When Admin sets the business date to "28 April 2025" And Admin runs inline COB job for Loan When Admin makes Credit Balance Refund transaction on "28 April 2025" with 48.07 EUR transaction amount - Then Loan status will be "CLOSED_OBLIGATIONS_MET" - Then Loan has 0 outstanding amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met # - CBR on closed loan is forbidden - # Then Credit Balance Refund transaction on active loan "28 April 2025" with 100 EUR transaction amount will result an error When Admin sets the business date to "06 May 2025" @@ -6680,11 +6687,14 @@ Feature: LoanAccrualActivity | 28 April 2025 | Accrual | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | false | | 29 April 2025 | Accrual | 0.09 | 0.0 | 0.09 | 0.0 | 0.0 | 0.0 | false | false | | 30 April 2025 | Accrual | 0.08 | 0.0 | 0.08 | 0.0 | 0.0 | 0.0 | false | false | - | 01 May 2025 | Repayment | 330.0 | 246.03 | 1.77 | 0.0 | 0.0 | 0.0 | true | false | + | 01 May 2025 | Repayment | 330.0 | 246.03 | 1.77 | 0.0 | 0.0 | 0.0 | true | false | | 01 May 2025 | Accrual | 4.87 | 0.0 | 4.87 | 0.0 | 0.0 | 0.0 | false | false | # - CBR on closed loan is forbidden - # Then Credit Balance Refund transaction on active loan "03 May 2025" with 100 EUR transaction amount will result an error + When Loan Pay-off is made on "03 May 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3697 Scenario: Verify accrual activity of overpaid loan in case of reversed MIR made before MIR and CBR for progressive loan - UC6 When Admin sets the business date to "21 March 2025" @@ -6722,8 +6732,7 @@ Feature: LoanAccrualActivity When Admin sets the business date to "28 March 2025" And Admin runs inline COB job for Loan When Admin makes Credit Balance Refund transaction on "28 March 2025" with 100 EUR transaction amount - Then Loan status will be "CLOSED_OBLIGATIONS_MET" - Then Loan has 0 outstanding amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met When Admin sets the business date to "02 April 2025" And Admin runs inline COB job for Loan When Customer undo "1"th "Repayment" transaction made on "21 March 2025" @@ -6798,7 +6807,7 @@ Feature: LoanAccrualActivity When Admin sets the business date to "06 May 2025" And Admin runs inline COB job for Loan And Customer makes "AUTOPAY" repayment on "06 May 2025" with 2.6 EUR transaction amount - Then Loan status will be "CLOSED_OBLIGATIONS_MET" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met Then Loan has 0 outstanding amount Then Loan Repayment schedule has 12 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 | @@ -6938,6 +6947,7 @@ Feature: LoanAccrualActivity When Admin sets the business date to "07 May 2025" And Admin runs inline COB job for Loan And Customer makes "AUTOPAY" repayment on "07 May 2025" with 73.68 EUR transaction amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met When Admin sets the business date to "08 May 2025" And Admin runs inline COB job for Loan Then Loan Repayment schedule has 12 periods, with the following data for periods: @@ -7099,6 +7109,7 @@ Feature: LoanAccrualActivity When Admin sets the business date to "07 May 2025" And Admin runs inline COB job for Loan And Customer makes "AUTOPAY" repayment on "07 May 2025" with 55.27 EUR transaction amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met Then Loan Repayment schedule has 13 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 | | | | 07 April 2025 | | 72.3 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -7219,8 +7230,7 @@ Feature: LoanAccrualActivity When Admin sets the business date to "28 March 2025" And Admin runs inline COB job for Loan When Admin makes Credit Balance Refund transaction on "28 March 2025" with 100 EUR transaction amount - Then Loan status will be "CLOSED_OBLIGATIONS_MET" - Then Loan has 0 outstanding amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met Then Loan Repayment schedule has 13 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 | | | | 21 March 2025 | | 242.46 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -7362,8 +7372,7 @@ Feature: LoanAccrualActivity | 21 April 2025 | Accrual | 0.08 | 0.0 | 0.08 | 0.0 | 0.0 | 0.0 | false | false | | 22 April 2025 | Accrual | 0.08 | 0.0 | 0.08 | 0.0 | 0.0 | 0.0 | false | false | And Customer makes "AUTOPAY" repayment on "23 April 2025" with 102.1 EUR transaction amount - Then Loan status will be "CLOSED_OBLIGATIONS_MET" - Then Loan has 0 outstanding amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met And Loan Transactions tab has the following data: | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | | 21 March 2025 | Disbursement | 242.46 | 0.0 | 0.0 | 0.0 | 0.0 | 242.46 | false | false | @@ -7553,8 +7562,7 @@ Feature: LoanAccrualActivity | 25 May 2025 | Accrual | 0.09 | 0.0 | 0.09 | 0.0 | 0.0 | 0.0 | false | false | Then Loan has 8.7 total unpaid payable due interest And Customer makes "AUTOPAY" repayment on "26 May 2025" with 107.75 EUR transaction amount - Then Loan status will be "CLOSED_OBLIGATIONS_MET" - Then Loan has 0 outstanding amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3802 Scenario: Correct Accrual Activity event publishing for backdated loans when the loan re-opens after reversing a goodwill credit transaction - UC1 @@ -7591,7 +7599,7 @@ Feature: LoanAccrualActivity And "Accrual Activity" transaction on "05 June 2023" got reverse-replayed on "24 June 2025" When Loan Pay-off is made on "24 June 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3803 Scenario: Correct Accrual Activity event publishing for backdated loans when the overpaid loan re-opens after reversing a goodwill credit transaction - UC2 @@ -7628,7 +7636,7 @@ Feature: LoanAccrualActivity And "Accrual Activity" transaction on "05 June 2023" got reverse-replayed on "24 June 2025" When Loan Pay-off is made on "24 June 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3805 Scenario: Correct Accrual Activity event publishing for backdated loans when the loan re-opens after reversing a payout refund transaction - UC3 @@ -7665,7 +7673,7 @@ Feature: LoanAccrualActivity And "Accrual Activity" transaction on "05 June 2023" got reverse-replayed on "24 June 2025" When Loan Pay-off is made on "24 June 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3806 Scenario: Correct Accrual Activity event publishing for backdated loans when the loan re-opens after reversing a merchant issue refund transaction - UC4 @@ -7703,7 +7711,7 @@ Feature: LoanAccrualActivity And "Accrual Activity" transaction on "05 June 2023" got reverse-replayed on "24 June 2025" When Loan Pay-off is made on "24 June 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3807 Scenario: Correct Accrual Activity event publishing for backdated loans when the loan re-opens after reversing a interest payment waiver transaction - UC5 @@ -7740,7 +7748,7 @@ Feature: LoanAccrualActivity And "Accrual Activity" transaction on "05 June 2023" got reverse-replayed on "24 June 2025" When Loan Pay-off is made on "24 June 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3808 Scenario: Correct Accrual Activity event publishing for backdated loans when the loan re-opens after reversing a repayment transaction - UC6 @@ -7777,7 +7785,7 @@ Feature: LoanAccrualActivity And "Accrual Activity" transaction on "05 June 2023" got reverse-replayed on "24 June 2025" When Loan Pay-off is made on "24 June 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C4052 Scenario: Verify that no extra accrual activity will be created upon loan reprocessing with merchant issued refund and NSF penalty @@ -8011,6 +8019,9 @@ Feature: LoanAccrualActivity | 18 July 2025 | Accrual Adjustment | 0.01 | 0.0 | 0.01 | 0.0 | 0.0 | 0.0 | false | false | | 18 July 2025 | Accrual | 0.01 | 0.0 | 0.01 | 0.0 | 0.0 | 0.0 | false | false | + When Admin makes Credit Balance Refund transaction on "18 July 2025" with 22.2 EUR transaction amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4054 Scenario: Verify that no extra accrual activity will be created upon loan reprocessing with merchant issued refund and SNOOZE fee When Admin sets the business date to "13 June 2025" @@ -8242,6 +8253,8 @@ Feature: LoanAccrualActivity | 18 July 2025 | Accrual | 2.8 | 0.0 | 0.0 | 2.8 | 0.0 | 0.0 | false | false | | 18 July 2025 | Accrual Adjustment | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false | | 18 July 2025 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false | + When Admin makes Credit Balance Refund transaction on "18 July 2025" with 22.2 EUR transaction amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3955 Scenario: Verify accrual activity trn just reversed but nt replayed with backdated repayment that overpays loan - UC1 @@ -8450,7 +8463,7 @@ Feature: LoanAccrualActivity And In Loan Transactions all transactions have non-null external-id When Admin makes Credit Balance Refund transaction on "06 October 2025" with 4.06 EUR transaction amount - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3956 Scenario: Verify accrual activity trn just reversed but not replayed with backdated repayment that fully pays loan and charge - UC2 @@ -8655,8 +8668,7 @@ Feature: LoanAccrualActivity When Admin runs inline COB job for Loan # --- backdated repayment on 01 August 2025 --- And Admin makes "REPAYMENT" transaction with "AUTOPAY" payment type on "01 August 2025" with 145.74 EUR transaction amount - Then Loan status will be "CLOSED_OBLIGATIONS_MET" - Then Loan has 0 outstanding amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met Then Loan Repayment schedule has 4 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 August 2025 | | 135.94 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -8830,8 +8842,7 @@ Feature: LoanAccrualActivity # --- backdated repayment on 01 August 2025 --- And Admin makes "REPAYMENT" transaction with "AUTOPAY" payment type on "01 August 2025" with 135.94 EUR transaction amount - Then Loan status will be "CLOSED_OBLIGATIONS_MET" - Then Loan has 0 outstanding amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met Then Loan Repayment schedule has 4 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 August 2025 | | 135.94 | | | 0.0 | | 0.0 | 0.0 | | | | diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanBuyDownFees.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanBuyDownFees.feature index 8cfeeb21406..c300e33bc8e 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanBuyDownFees.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanBuyDownFees.feature @@ -349,7 +349,7 @@ Feature:Feature: Buy Down Fees | 01 February 2024 | Repayment | 33.72 | 33.14 | 0.58 | 0.0 | 0.0 | 66.86 | false | When Admin sets the business date to "1 March 2024" When Loan Pay-off is made on "1 March 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met 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 | @@ -420,7 +420,7 @@ Feature:Feature: Buy Down Fees When Admin sets the business date to "1 March 2024" When Admin runs inline COB job for Loan When Loan Pay-off is made on "1 March 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met And 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 | @@ -629,8 +629,9 @@ Feature:Feature: Buy Down Fees | Date | Fee Amount | Amortized Amount | Not Yet Amortized Amount | Adjusted Amount | Charged Off Amount | | 01 January 2024 | 50.0 | 33.52 | 0.0 | 0.0 | 16.48 | And LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent is created on "01 March 2024" + When Loan Pay-off is made on "1 March 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3829 Scenario: Verify loan with Buy Down fees and charge-off transaction - daily amortization and amortization in case of loan charge-off event - UC3.2 @@ -835,7 +836,7 @@ Feature:Feature: Buy Down Fees | 01 January 2024 | 50.0 | 33.52 | 0.0 | 0.0 | 16.48 | And LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent is created on "01 March 2024" When Loan Pay-off is made on "1 March 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3848 Scenario: Verify loan with Buy Down fees and undo the charge-off transaction - amortization in case of loan charge-off event should also be reversed - UC3.3 @@ -935,7 +936,7 @@ Feature:Feature: Buy Down Fees | Date | Fee Amount | Amortized Amount | Not Yet Amortized Amount | Adjusted Amount | Charged Off Amount | | 01 January 2024 | 50.0 | 17.58 | 32.42 | 0.0 | 0.0 | When Loan Pay-off is made on "1 February 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3849 Scenario: Verify loan with Buy Down fees and undo the charge-off a fraud loan - amortization in case of loan charge-off event should also be reversed - UC3.4 @@ -1036,7 +1037,7 @@ Feature:Feature: Buy Down Fees | Date | Fee Amount | Amortized Amount | Not Yet Amortized Amount | Adjusted Amount | Charged Off Amount | | 01 January 2024 | 50.0 | 17.58 | 32.42 | 0.0 | 0.0 | When Loan Pay-off is made on "1 February 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3850 Scenario: Verify loan with Buy Down fees and charge-off with "delinquent" reason - amortization in case of loan charge-off event - UC3.5 @@ -1099,7 +1100,7 @@ Feature:Feature: Buy Down Fees | 01 January 2024 | 50.0 | 13.74 | 0.0 | 0.0 | 36.26 | And LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent is created on "25 January 2024" When Loan Pay-off is made on "25 January 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3851 Scenario: Verify loan with Buy Down fees and charge-off a fraud loan - amortization in case of loan charge-off event - UC3.6 @@ -1161,7 +1162,7 @@ Feature:Feature: Buy Down Fees | 01 January 2024 | 50.0 | 13.74 | 0.0 | 0.0 | 36.26 | And LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent is created on "25 January 2024" When Loan Pay-off is made on "25 January 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3852 Scenario: Verify loan with Buy Down fees and undo the charge-off transaction with "delinquent" reason - amortization in case of loan charge-off event should also be reversed - UC3.7 @@ -1248,7 +1249,7 @@ Feature:Feature: Buy Down Fees | Date | Fee Amount | Amortized Amount | Not Yet Amortized Amount | Adjusted Amount | Charged Off Amount | | 01 January 2024 | 50.0 | 13.74 | 36.26 | 0.0 | 0.0 | When Loan Pay-off is made on "25 January 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3886 Scenario: Verify loan with with a few Buy Down fees with adjustment and charge-off transaction - amortization in case of loan charge-off event - UC3.8 @@ -1335,7 +1336,7 @@ Feature:Feature: Buy Down Fees | 01 February 2024 | 50.0 | 25.0 | 0.0 | 0.0 | 25.0 | And LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent is created on "01 March 2024" When Loan Pay-off is made on "1 March 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:С3825 Scenario: Verify loan with Buy Down Fee adjustment trn and repayment trns - UC4 @@ -1431,7 +1432,7 @@ Feature:Feature: Buy Down Fees | 01 January 2024 | 50.0 | 40.0 | 0.0 | 10.0 | 0.0 | And LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent is created on "31 March 2024" When Loan Pay-off is made on "1 April 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met 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 | @@ -1548,7 +1549,7 @@ Feature:Feature: Buy Down Fees | 01 January 2024 | 50.0 | 35.0 | 0.0 | 15.0 | 0.0 | And LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent is created on "31 March 2024" When Loan Pay-off is made on "1 April 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met 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 | @@ -1597,6 +1598,7 @@ Feature:Feature: Buy Down Fees And LoanBuyDownFeeTransactionCreatedBusinessEvent is created on "02 January 2024" # --- make write-off --- # And Admin does write-off the loan on "02 January 2024" + Then Loan has 0 outstanding amount Then Loan status will be "CLOSED_WRITTEN_OFF" Then Loan Repayment schedule has 3 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 | @@ -2179,6 +2181,9 @@ Feature:Feature: Buy Down Fees | 01 January 2024 | 50.0 | 34.07 | 15.93 | 0.0 | 0.0 | And LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent is created on "02 March 2024" + When Loan Pay-off is made on "03 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3887 Scenario: Verify Buy Down Fee reversal - UC6 When Admin sets the business date to "01 January 2024" @@ -2459,6 +2464,9 @@ Feature:Feature: Buy Down Fees | LIABILITY | 145024 | Deferred Capitalized Income | 50.0 | | And LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent is created on "16 February 2024" + When Loan Pay-off is made on "17 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3888 Scenario: Verify Buy Down Fee reversal on same business date When Admin sets the business date to "01 January 2024" @@ -2519,6 +2527,9 @@ Feature:Feature: Buy Down Fees | EXPENSE | 450280 | Buy Down Expense | | 50.0 | | LIABILITY | 145024 | Deferred Capitalized Income | 50.0 | | + When Loan Pay-off is made on "02 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3889 Scenario: Verify Buy Down Fee reversal forbidden when adjustment exists When Admin sets the business date to "01 January 2024" @@ -2658,6 +2669,9 @@ Feature:Feature: Buy Down Fees | 11 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | And LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent is created on "11 January 2024" + When Loan Pay-off is made on "12 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3981 Scenario: Verify loan with Buy Down fees and full payment for non-merchant - UC1 When Admin sets the business date to "01 January 2024" @@ -2782,6 +2796,8 @@ Feature:Feature: Buy Down Fees | LIABILITY | 145024 | Deferred Capitalized Income | | 50.0 | | LIABILITY | 145023 | Suspense/Clearing account | | 50.0 | | LIABILITY | 145024 | Deferred Capitalized Income | 50.0 | | + When Loan Pay-off is made on "02 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3983 Scenario: Verify loan with Buy Down fees and undo the charge-off transaction for non merchant - amortization in case of loan charge-off event is also reversed - UC3.1 @@ -2880,8 +2896,9 @@ Feature:Feature: Buy Down Fees And Buy down fee by external-id contains the following data: | Date | Fee Amount | Amortized Amount | Not Yet Amortized Amount | Adjusted Amount | Charged Off Amount | | 01 January 2024 | 50.0 | 17.58 | 32.42 | 0.0 | 0.0 | - When Loan Pay-off is made on "1 February 2024" - Then Loan's all installments have obligations met + + When Loan Pay-off is made on "01 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3984 Scenario: Verify loan with Buy Down fees and undo the charge-off a fraud loan for non-merchant - amortization in case of loan charge-off event is also reversed - UC3.2 @@ -2981,8 +2998,8 @@ Feature:Feature: Buy Down Fees And Buy down fee by external-id contains the following data: | Date | Fee Amount | Amortized Amount | Not Yet Amortized Amount | Adjusted Amount | Charged Off Amount | | 01 January 2024 | 50.0 | 17.58 | 32.42 | 0.0 | 0.0 | - When Loan Pay-off is made on "1 February 2024" - Then Loan's all installments have obligations met + When Loan Pay-off is made on "01 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3985 Scenario: Verify loan with Buy Down fees and undo the charge-off transaction with "delinquent" reason for non-merchant - amortization in case of loan charge-off event is also reversed - UC3.3 @@ -3069,7 +3086,7 @@ Feature:Feature: Buy Down Fees | Date | Fee Amount | Amortized Amount | Not Yet Amortized Amount | Adjusted Amount | Charged Off Amount | | 01 January 2024 | 50.0 | 13.74 | 36.26 | 0.0 | 0.0 | When Loan Pay-off is made on "25 January 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:С3986 Scenario: Verify loan with Buy Down Fee adjustment trn and repayment trns for non-merchant - UC4 @@ -3241,6 +3258,9 @@ Feature:Feature: Buy Down Fees And Admin adds buy down fee adjustment with "AUTOPAY" payment type to the loan on "01 January 2024" with "25" EUR transaction amount And Loan Transactions tab has a "Buy Down Fee Adjustment" transaction with date "01 January 2024" which has classification code value "buydown_fee_transaction_classification_value" + When Loan Pay-off is made on "01 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4009 Scenario: Verify Buy Down Fee amortization allocation mappings When Admin sets the business date to "1 January 2024" @@ -3291,6 +3311,9 @@ Feature:Feature: Buy Down Fees | Date | Type | Amount | | 02 January 2024 | AM | 1.11 | + When Loan Pay-off is made on "03 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4019 Scenario: Verify Buy Down Fee amortization allocation mappings when buy down fee transaction is reversed When Admin sets the business date to "1 January 2024" @@ -3387,6 +3410,9 @@ Feature:Feature: Buy Down Fees | 03 January 2024 | AM | 2.22 | | 04 January 2024 | AM | 2.23 | + When Loan Pay-off is made on "05 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4022 Scenario: Verify Buy Down Fee amortization allocation mappings when buy down fee adjustment occurs When Admin sets the business date to "1 January 2024" @@ -3555,6 +3581,9 @@ Feature:Feature: Buy Down Fees | 05 January 2024 | AM_ADJ | 0.25 | | 06 January 2024 | AM | 0.43 | + When Loan Pay-off is made on "07 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4040 Scenario: Verify Buy Down Fee amortization allocation mapping when already amortized amount is greater than should be after buy down fee adjustment When Admin sets the business date to "1 January 2024" @@ -3634,6 +3663,9 @@ Feature:Feature: Buy Down Fees | Date | Fee Amount | Amortized Amount | Not Yet Amortized Amount | Adjusted Amount | Charged Off Amount | | 01 January 2024 | 1.0 | 0.3 | 0.0 | 0.7 | 0.0 | + When Loan Pay-off is made on "25 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4043 Scenario: Verify Buy Down Fee amortization allocation mapping when after buy down fee adjustment and charge-off When Admin sets the business date to "1 January 2024" @@ -3773,6 +3805,9 @@ Feature:Feature: Buy Down Fees | Date | Fee Amount | Amortized Amount | Not Yet Amortized Amount | Adjusted Amount | Charged Off Amount | | 01 January 2024 | 1.0 | 0.5 | 0.0 | 0.3 | 0.2 | + When Loan Pay-off is made on "16 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4092 Scenario: Verify GL entries for Buydown Fee Amortization - UC1: Amortization for Buydown fee with NO classification rule When Admin sets the business date to "01 January 2024" @@ -3794,6 +3829,9 @@ Feature:Feature: Buy Down Fees | INCOME | 450281 | Income From Buy Down | | 0.55 | | LIABILITY | 145024 | Deferred Capitalized Income | 0.55 | | + When Loan Pay-off is made on "02 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4093 Scenario: Verify GL entries for Buydown Fee Amortization - UC2: Amortization for Buydown fee with classification rule: pending_bankruptcy When Admin sets the business date to "01 January 2024" @@ -3815,6 +3853,9 @@ Feature:Feature: Buy Down Fees | INCOME | 404007 | Fee Income | | 0.55 | | LIABILITY | 145024 | Deferred Capitalized Income | 0.55 | | + When Loan Pay-off is made on "02 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4094 Scenario: Verify GL entries for Buydown Fee Amortization - UC3: Amortization for Buydown fees with NO classification and with classification rule: pending_bankruptcy When Admin sets the business date to "01 January 2024" @@ -3848,6 +3889,9 @@ Feature:Feature: Buy Down Fees | INCOME | 450281 | Income From Buy Down | | 0.55 | | LIABILITY | 145024 | Deferred Capitalized Income | 0.77 | | + When Loan Pay-off is made on "02 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4116 Scenario: Verify Buy Down Fee journal entries values when backdated new buy down fee with no classification and buy down fee adjustment for existing one with classification occurs on the same day When Admin sets the business date to "01 January 2024" @@ -3939,6 +3983,9 @@ Feature:Feature: Buy Down Fees | LIABILITY | 145024 | Deferred Capitalized Income | 30.0 | | | INCOME | 404007 | Fee Income | 5.0 | | + When Loan Pay-off is made on "16 April 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4117 Scenario: Verify Buy Down Fee journal entries values when backdated new buy down fee and buy down fee adjustment for existing one occurs on the same day, no classification When Admin sets the business date to "01 January 2024" @@ -4028,3 +4075,6 @@ Feature:Feature: Buy Down Fees | LIABILITY | 145024 | Deferred Capitalized Income | | 5.0 | | LIABILITY | 145024 | Deferred Capitalized Income | 30.0 | | | INCOME | 450281 | Income From Buy Down | 5.0 | | + + When Loan Pay-off is made on "16 April 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanCapitalizedIncome.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanCapitalizedIncome.feature index 007a5fed6c3..f9d35d1302b 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanCapitalizedIncome.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanCapitalizedIncome.feature @@ -35,6 +35,9 @@ Feature: Capitalized Income | Amount | Amortized Amount | Unrecognized Amount | Adjusted Amount | Charged Off Amount | | 100.0 | 0.0 | 100.0 | 0.0 | 0.0 | + When Loan Pay-off is made on "02 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3637 Scenario: As a user I want to add capitalized income to a progressive loan after disbursement - UC2 When Admin sets the business date to "1 January 2024" @@ -64,6 +67,9 @@ Feature: Capitalized Income | ASSET | 112601 | Loans Receivable | 100.0 | | | LIABILITY | 145024 | Deferred Capitalized Income | | 100.0 | + When Loan Pay-off is made on "02 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3638 Scenario: Verify capitalized income amount with disbursement amount calculation within approved amount for multidisbursal progressive loan - UC3 When Admin sets the business date to "1 January 2024" @@ -102,6 +108,9 @@ Feature: Capitalized Income | ASSET | 112601 | Loans Receivable | 200.0 | | | LIABILITY | 145024 | Deferred Capitalized Income | | 200.0 | + When Loan Pay-off is made on "03 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3639 Scenario: Verify validation of capitalized income amount with disbursement amount within approved amount for progressive loan - UC4 When Admin sets the business date to "1 January 2024" @@ -115,6 +124,9 @@ Feature: Capitalized Income When Admin sets the business date to "2 January 2024" Then Capitalized income with payment type "AUTOPAY" on "02 January 2024" is forbidden with amount "200" while exceed approved amount + When Loan Pay-off is made on "02 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3640 Scenario: Verify validation of capitalized income amount with disbursement amount within approved amount for multidisbursal progressive loan - UC5 When Admin sets the business date to "1 January 2024" @@ -129,6 +141,9 @@ Feature: Capitalized Income And Admin successfully disburse the loan on "2 January 2024" with "300" EUR transaction amount Then Capitalized income with payment type "AUTOPAY" on "2 January 2024" is forbidden with amount "300" while exceed approved amount + When Loan Pay-off is made on "02 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3641 Scenario: Verify validation of capitalized income amount with disbursement amount within approved amount after undo disbursement - UC6 When Admin sets the business date to "1 January 2024" @@ -179,6 +194,9 @@ Feature: Capitalized Income | ASSET | 112601 | Loans Receivable | 200.0 | | | LIABILITY | 145024 | Deferred Capitalized Income | | 200.0 | + When Loan Pay-off is made on "03 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3642 Scenario: Verify capitalized income amount with disbursement amount calculation within approved amount for multidisbursal loan after undo disbursement - UC7 When Admin sets the business date to "1 January 2024" @@ -247,7 +265,7 @@ Feature: Capitalized Income | LIABILITY | 145024 | Deferred Capitalized Income | | 300.0 | When Loan Pay-off is made on "04 January 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3720 Scenario: Verify capitalized income amount with disbursement amount calculation within approved amount for multidisbursal loan - UC8 @@ -286,7 +304,7 @@ Feature: Capitalized Income Then Capitalized income with payment type "AUTOPAY" on "02 January 2024" is forbidden with amount "200" while exceed approved amount When Loan Pay-off is made on "02 January 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3721 Scenario: Verify capitalized income amount with disbursement amount calculation within approved amount for multidisbursal loan with undo last disbursal - UC9 @@ -367,7 +385,7 @@ Feature: Capitalized Income Then Capitalized income with payment type "AUTOPAY" on "04 January 2024" is forbidden with amount "200" while exceed approved amount When Loan Pay-off is made on "04 January 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3723 Scenario: Verify capitalized income with disbursement amount calculation within approved amount for multidisbursal loan with undo capitalized income - UC10 @@ -445,7 +463,7 @@ Feature: Capitalized Income Then Capitalized income with payment type "AUTOPAY" on "04 January 2024" is forbidden with amount "300" while exceed approved amount When Loan Pay-off is made on "04 January 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3730 Scenario: Verify capitalized income amount with disbursement amount calculation within approved over applied amount with percentage type for multidisbursal loan - UC11 @@ -512,7 +530,7 @@ Feature: Capitalized Income Then Capitalized income with payment type "AUTOPAY" on "04 January 2024" is forbidden with amount "100" while exceed approved amount When Loan Pay-off is made on "04 January 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3764 Scenario: Verify capitalized income with disbursement amount within approved over applied amount with flat type with undo last disbursal for multidisbursal loan - UC12 @@ -578,7 +596,7 @@ Feature: Capitalized Income Then Capitalized income with payment type "AUTOPAY" on "03 January 2024" is forbidden with amount "300" while exceed approved amount When Loan Pay-off is made on "03 January 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3765 Scenario: Verify capitalized income with disbursement amount within approved over applied amount with percentage type with undo disbursal for single disbursal loan - UC13 @@ -640,7 +658,7 @@ Feature: Capitalized Income Then Capitalized income with payment type "AUTOPAY" on "04 January 2024" is forbidden with amount "100" while exceed approved amount When Loan Pay-off is made on "04 January 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3766 Scenario: Verify capitalized income with adjustment amount with disbursement amount within approved over applied amount with flat type for single disbursal loan - UC14 @@ -686,7 +704,7 @@ Feature: Capitalized Income Then Capitalized income with payment type "AUTOPAY" on "02 January 2024" is forbidden with amount "200" while exceed approved amount When Loan Pay-off is made on "02 January 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3776 Scenario: Verify capitalized income amount with disbursement amount calculation within approved over applied amount with percentage type for multidisbursal loan - UC15 @@ -750,7 +768,7 @@ Feature: Capitalized Income Then Capitalized income with payment type "AUTOPAY" on "04 January 2024" is forbidden with amount "100" while exceed approved amount When Loan Pay-off is made on "04 January 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3777 Scenario: Verify capitalized income with disbursement amount within approved over applied amount with flat type with undo last disbursal for multidisbursal loan - UC16 @@ -816,7 +834,7 @@ Feature: Capitalized Income Then Capitalized income with payment type "AUTOPAY" on "03 January 2024" is forbidden with amount "300" while exceed approved amount When Loan Pay-off is made on "03 January 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3778 Scenario: Verify capitalized income with disbursement amount within approved over applied amount with percentage type with undo disbursal for single disbursal loan - UC17 @@ -878,7 +896,7 @@ Feature: Capitalized Income Then Capitalized income with payment type "AUTOPAY" on "04 January 2024" is forbidden with amount "100" while exceed approved amount When Loan Pay-off is made on "04 January 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3779 Scenario: Verify capitalized income with adjustment amount with disbursement amount within approved over applied amount with flat type for single disbursal loan - UC18 @@ -927,7 +945,7 @@ Feature: Capitalized Income Then Capitalized income with payment type "AUTOPAY" on "02 January 2024" is forbidden with amount "200" while exceed approved amount When Loan Pay-off is made on "02 January 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3646 Scenario: As a user I want to add capitalized income to a progressive loan after disbursement and then make a full repayment - amortization in case of loan close event @@ -958,6 +976,7 @@ Feature: Capitalized Income | ASSET | 112601 | Loans Receivable | 100.0 | | | LIABILITY | 145024 | Deferred Capitalized Income | | 100.0 | When Customer makes "REPAYMENT" transaction with "AUTOPAY" payment type on "2 January 2024" with 1000.17 EUR transaction amount and system-generated Idempotency key + Then Loan is closed with zero outstanding balance and it's all installments have obligations met Then Loan Repayment schedule has 1 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 | | 900.0 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -1032,6 +1051,9 @@ Feature: Capitalized Income | LIABILITY | 145024 | Deferred Capitalized Income | 100.0 | | And LoanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent is raised on "02 January 2024" + When Admin makes Credit Balance Refund transaction on "02 January 2024" with 99.83 EUR transaction amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3651 Scenario: As a user I want to add capitalized income to a progressive loan after disbursement and then write off loan - amortization in case of loan close event When Admin sets the business date to "1 January 2024" @@ -1265,6 +1287,9 @@ Feature: Capitalized Income | 50.0 | 50.0 | 0.0 | 0.0 | 0.0 | And Loan Capitalized Income Amortization Transaction Created Business Event is created on "31 March 2024" + When Loan Pay-off is made on "01 April 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3649 Scenario: Verify capitalized income: daily amortization - Capitalized Income type: fee When Admin sets the business date to "01 January 2024" @@ -1445,6 +1470,9 @@ Feature: Capitalized Income | LIABILITY | 145024 | Deferred Capitalized Income | 0.55 | | And Loan Capitalized Income Amortization Transaction Created Business Event is created on "31 March 2024" + When Loan Pay-off is made on "01 April 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3661 Scenario: As a user I want to add capitalized income to a progressive loan after disbursement and then charge-off the loan with "delinquent" reason - amortization in case of loan charge-off event When Admin sets the business date to "1 January 2024" @@ -1491,6 +1519,9 @@ Feature: Capitalized Income | LIABILITY | 145024 | Deferred Capitalized Income | 16.67 | | Then LoanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent is raised on "26 January 2024" + When Loan Pay-off is made on "26 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3662 Scenario: As a user I want to add capitalized income to a progressive loan after disbursement and then charge-off a fraud loan - amortization in case of loan charge-off event When Admin sets the business date to "1 January 2024" @@ -1540,6 +1571,9 @@ Feature: Capitalized Income | 100.0 | 83.33 | 0.0 | 0.0 | 16.67 | Then LoanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent is raised on "26 January 2024" + When Loan Pay-off is made on "26 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3663 Scenario: As a user I want to add capitalized income to a progressive loan after disbursement and then charge-off the loan - amortization in case of loan charge-off event When Admin sets the business date to "1 January 2024" @@ -1589,6 +1623,9 @@ Feature: Capitalized Income | 100.0 | 83.33 | 0.0 | 0.0 | 16.67 | Then LoanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent is raised on "26 January 2024" + When Loan Pay-off is made on "26 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3664 Scenario: As a user I want to add capitalized income to a progressive loan after disbursement and then undo the charge-off transaction with "delinquent" reason - amortization in case of loan charge-off event should also be reversed When Admin sets the business date to "1 January 2024" @@ -1661,6 +1698,10 @@ Feature: Capitalized Income | Amount | Amortized Amount | Unrecognized Amount | Adjusted Amount | Charged Off Amount | | 100.0 | 83.33 | 16.67 | 0.0 | 0.0 | + When Loan Pay-off is made on "26 January 2024" + And Customer makes "AUTOPAY" repayment on "26 January 2024" with 225 EUR transaction amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3673 Scenario: Verify capitalized income: repayment schedule - UC1: Simple loan - full payment When Admin sets the business date to "01 January 2024" @@ -1916,7 +1957,7 @@ Feature: Capitalized Income And Admin sets the business date to "01 April 2024" And Admin runs inline COB job for Loan And Customer makes "AUTOPAY" repayment on "01 April 2024" with 50.59 EUR transaction amount - Then Loan status will be "CLOSED_OBLIGATIONS_MET" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met Then Loan Repayment schedule has 3 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 | | | | @@ -2232,7 +2273,7 @@ Feature: Capitalized Income When Admin sets the business date to "01 March 2024" And Admin runs inline COB job for Loan And Loan Pay-off is made on "01 March 2024" - Then Loan status will be "CLOSED_OBLIGATIONS_MET" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met And Loan Repayment schedule has 3 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 | | | | @@ -2628,6 +2669,9 @@ Feature: Capitalized Income | 01 March 2024 | Charge-off | 101.17 | 100.29 | 0.88 | 0.0 | 0.0 | 0.0 | false | false | | 01 March 2024 | Capitalized Income Amortization | 16.48 | 0.0 | 16.48 | 0.0 | 0.0 | 0.0 | false | false | + When Loan Pay-off is made on "01 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3665 Scenario: Verify Capitalized Income Adjustment with partial amortization and allocation strategy - Credit Adj < Bal - UC4 When Admin sets the business date to "01 January 2024" @@ -2717,6 +2761,7 @@ Feature: Capitalized Income | 01 March 2024 | Capitalized Income Adjustment | 10.0 | 10.0 | 0.0 | 0.0 | 0.0 | 40.3 | false | When Admin sets the business date to "01 April 2024" And Customer makes "REPAYMENT" transaction with "AUTOPAY" payment type on "01 April 2024" with 40.54 EUR transaction amount and system-generated Idempotency key + Then Loan is closed with zero outstanding balance and it's all installments have obligations met 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 | @@ -2866,6 +2911,7 @@ Feature: Capitalized Income | 50.0 | 17.58 | 17.42 | 15.0 | 0.0 | When Admin sets the business date to "01 April 2024" And Customer makes "REPAYMENT" transaction with "AUTOPAY" payment type on "01 April 2024" with 35.52 EUR transaction amount and system-generated Idempotency key + Then Loan is closed with zero outstanding balance and it's all installments have obligations met 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 | @@ -2907,7 +2953,6 @@ Feature: Capitalized Income | Type | Account code | Account name | Debit | Credit | | ASSET | 112601 | Loans Receivable | | 5.0 | | LIABILITY | 145024 | Deferred Capitalized Income | 5.0 | | - Then Loan status will be "CLOSED_OBLIGATIONS_MET" @TestRailId:C3702 Scenario: Verify Capitalized Income adjustment reverse replay with backdated repayment transaction @@ -3186,6 +3231,9 @@ Feature: Capitalized Income | ASSET | 112603 | Interest/Fee Receivable | | 0.87 | | LIABILITY | 145024 | Deferred Capitalized Income | 50.0 | | + When Loan Pay-off is made on "01 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3703 Scenario: Verify Capitalized Income adjustment reverse replay with backdated charge When Admin sets the business date to "01 January 2024" @@ -3468,6 +3516,9 @@ Feature: Capitalized Income | Amount | Amortized Amount | Unrecognized Amount | Adjusted Amount | Charged Off Amount | | 51.0 | 0.0 | 0.0 | 51.0 | 0.0 | + When Loan Pay-off is made on "01 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3712 Scenario: Verify Capitalized Income Adjustment validation - Total adjustment amount cannot exceed original transaction amount When Admin sets the business date to "01 January 2024" @@ -3483,6 +3534,9 @@ Feature: Capitalized Income # Try to adjust more than original capitalized income amount (50 EUR) - should fail And Admin adds invalid capitalized income adjustment with "AUTOPAY" payment type to the loan on "01 February 2024" with "60" EUR transaction amount + When Loan Pay-off is made on "01 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3713 Scenario: Verify Capitalized Income Adjustment validation - Adjustment transaction date cannot be earlier than original transaction date When Admin sets the business date to "01 January 2024" @@ -3498,6 +3552,9 @@ Feature: Capitalized Income # Try to adjust with date earlier than original transaction (31 December 2023) - should fail And Admin adds invalid capitalized income adjustment with "AUTOPAY" payment type to the loan on "31 December 2024" with "60" EUR transaction amount + When Loan Pay-off is made on "01 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3714 Scenario: Verify Capitalized Income Adjustment validation - Multiple adjustments cannot exceed original amount When Admin sets the business date to "01 January 2024" @@ -3513,7 +3570,10 @@ Feature: Capitalized Income And Admin adds capitalized income adjustment with "AUTOPAY" payment type to the loan on "01 February 2024" with "30" EUR transaction amount When Admin sets the business date to "01 March 2024" # Try to add another adjustment that would exceed total - And Admin adds invalid capitalized income adjustment with "AUTOPAY" payment type to the loan on "01 Marcj 2024" with "25" EUR transaction amount + And Admin adds invalid capitalized income adjustment with "AUTOPAY" payment type to the loan on "01 March 2024" with "25" EUR transaction amount + + When Loan Pay-off is made on "01 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3715 Scenario: Verify Capitalized Income Adjustment - Balance cannot go negative, set to zero instead @@ -3553,6 +3613,7 @@ Feature: Capitalized Income When Customer makes "REPAYMENT" transaction with "AUTOPAY" payment type on "01 March 2024" with 50.89 EUR transaction amount and system-generated Idempotency key When Admin sets the business date to "02 March 2024" And Admin adds capitalized income adjustment with "AUTOPAY" payment type to the loan on "02 March 2024" with "50" EUR transaction amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met Then Loan Repayment schedule has 3 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 | | | | @@ -3598,6 +3659,9 @@ Feature: Capitalized Income And Admin adds capitalized income adjustment with "AUTOPAY" payment type to the loan on "01 February 2024" with "30" EUR transaction amount Then Capitalized income adjustment with payment type "AUTOPAY" on "01 April 2024" is forbidden with amount "10" due to future date + When Loan Pay-off is made on "01 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3717 Scenario: Verify Capitalized Income validation while run COB at first day of loan When Admin sets the business date to "01 January 2024" @@ -3631,6 +3695,9 @@ Feature: Capitalized Income | 01 January 2024 | Capitalized Income | 50.0 | 50.0 | 0.0 | 0.0 | 0.0 | 150.0 | false | false | | 01 January 2024 | Capitalized Income Amortization | 0.55 | 0.0 | 0.55 | 0.0 | 0.0 | 0.0 | false | false | + When Loan Pay-off is made on "02 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3718 Scenario: Verify Capitalized Income Adjustment validation while run COB at first day of loan When Admin sets the business date to "01 January 2024" @@ -3670,6 +3737,9 @@ Feature: Capitalized Income | Amount | Amortized Amount | Unrecognized Amount | Adjusted Amount | Charged Off Amount | | 50.0 | 0.11 | 9.89 | 40.0 | 0.0 | + When Loan Pay-off is made on "02 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3704 Scenario: Verify Capitalized Income adjustment reverse - UC1 When Admin sets the business date to "01 January 2024" @@ -3960,6 +4030,9 @@ Feature: Capitalized Income | Amount | Amortized Amount | Unrecognized Amount | Adjusted Amount | Charged Off Amount | | 50.0 | 34.07 | 15.93 | 0.0 | 0.0 | + When Loan Pay-off is made on "03 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3705 Scenario: Verify Capitalized Income adjustment reverse - UC2 When Admin sets the business date to "01 January 2024" @@ -4042,6 +4115,9 @@ Feature: Capitalized Income | ASSET | 112601 | Loans Receivable | 40.0 | | | LIABILITY | 145024 | Deferred Capitalized Income | | 40.0 | + When Loan Pay-off is made on "12 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3706 Scenario: Verify Capitalized Income adjustment reverse - UC3 When Admin sets the business date to "01 January 2024" @@ -4128,6 +4204,9 @@ Feature: Capitalized Income | ASSET | 112603 | Interest/Fee Receivable | 0.25 | | | LIABILITY | 145024 | Deferred Capitalized Income | | 55.0 | + When Loan Pay-off is made on "12 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3756 Scenario: Verify Capitalised Income Adjustment reversed on same biz date when added - UC4 When Admin sets the business date to "01 January 2024" @@ -4198,7 +4277,7 @@ Feature: Capitalized Income | 04 January 2024 | Capitalized Income Amortization | 1.1 | 0.0 | 1.1 | 0.0 | 0.0 | 0.0 | false | false | When Loan Pay-off is made on "05 January 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3708 Scenario: Verify capitalized income reversed after repayment - UC1 @@ -4530,6 +4609,9 @@ Feature: Capitalized Income Then LoanCapitalizedIncomeAmortizationAdjustmentTransactionCreatedBusinessEvent is raised on "14 February 2024" Then Customer is forbidden to undo "1"th "Capitalized Income" transaction made on "01 January 2024" due to transaction type is non-reversal + When Loan Pay-off is made on "16 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3737 Scenario: Verify overpayment amount when capitalized income transactions are reversed and replayed - basic flow When Admin sets the business date to "1 January 2024" @@ -4568,6 +4650,9 @@ Feature: Capitalized Income Then Loan status will be "OVERPAID" Then Loan has 299.25 overpaid amount + When Admin makes Credit Balance Refund transaction on "5 January 2024" with 299.25 EUR transaction amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3739 Scenario: Verify multiple capitalized income transactions reversal with overpayment - selective middle transaction reversal When Admin sets the business date to "1 January 2024" @@ -4613,6 +4698,9 @@ Feature: Capitalized Income Then Loan status will be "OVERPAID" Then Loan has 197.18 overpaid amount + When Admin makes Credit Balance Refund transaction on "15 January 2024" with 197.18 EUR transaction amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3740 Scenario: Verify capitalized income reversal with partial repayment when loan transitions from active to overpaid state When Admin sets the business date to "1 January 2024" @@ -4642,6 +4730,9 @@ Feature: Capitalized Income And Loan has 0.0 outstanding amount And Loan has 199.25 overpaid amount + When Admin makes Credit Balance Refund transaction on "5 January 2024" with 199.25 EUR transaction amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3741 Scenario: Verify backdated disbursement with capitalized income and overpayment reverse-replay When Admin sets the business date to "1 January 2024" @@ -4677,6 +4768,9 @@ Feature: Capitalized Income | 10 January 2024 | Repayment | 750.0 | 748.87 | 1.13 | 0.0 | 0.0 | 251.13 | false | true | And Loan has 255.09 outstanding amount + When Loan Pay-off is made on "10 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3742 Scenario: Verify capitalized income amortization reversal when multiple payments create complex overpayment scenario When Admin sets the business date to "1 January 2024" @@ -4722,6 +4816,9 @@ Feature: Capitalized Income And Loan has 0.0 outstanding amount And Loan has 398.53 overpaid amount + When Admin makes Credit Balance Refund transaction on "08 January 2024" with 398.53 EUR transaction amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3743 Scenario: Verify Capitalized income and Caplitalized income adjustment - Accounting and repayment schedule handling in case of loan is overpaid (Capitalized Income Scenarios - UC9) When Admin sets the business date to "1 January 2024" @@ -5390,6 +5487,9 @@ Feature: Capitalized Income | 15 April 2024 | Capitalized Income Adjustment | 15.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | | 15 April 2024 | Capitalized Income Amortization Adjustment | 15.0 | 0.0 | 15.0 | 0.0 | 0.0 | 0.0 | false | false | + When Admin makes Credit Balance Refund transaction on "15 April 2024" with 15 EUR transaction amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @Skip @TestRailId:C3744 Scenario: Verify Capitalized income and Caplitalized income adjustment - Accounting and repayment schedule handling in case of loan is overpaid (Capitalized Income Scenarios - UC10) When Admin sets the business date to "1 January 2024" @@ -5850,6 +5950,9 @@ Feature: Capitalized Income | 15 April 2024 | Capitalized Income Adjustment | 15.0 | 9.71 | 0.29 | 0.0 | 0.0 | 0.0 | false | false | | 15 April 2024 | Capitalized Income Amortization Adjustment | 15.0 | 0.0 | 15.0 | 0.0 | 0.0 | 0.0 | false | false | + When Admin makes Credit Balance Refund transaction on "15 April 2024" with 5 EUR transaction amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3745 Scenario: Verify Capitalized income and Caplitalized income adjustment - Accounting and repayment schedule handling in case of loan is overpaid (Capitalized Income Scenarios - UC11) When Admin sets the business date to "1 January 2024" @@ -6420,6 +6523,9 @@ Feature: Capitalized Income | 15 March 2024 | Credit Balance Refund | 0.16 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | | 16 March 2024 | Capitalized Income | 50.0 | 50.0 | 0.0 | 0.0 | 0.0 | 50.0 | false | false | + When Loan Pay-off is made on "16 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3746 Scenario: Verify Capitalized income and Caplitalized income adjustment - Accounting and repayment schedule handling in case of loan is overpaid (Capitalized Income Scenarios - UC12) When Admin sets the business date to "1 January 2024" @@ -6815,6 +6921,9 @@ Feature: Capitalized Income | 15 March 2024 | Capitalized Income Amortization | 9.34 | 0.0 | 9.34 | 0.0 | 0.0 | 0.0 | false | false | | 16 March 2024 | Capitalized Income | 50.0 | 50.0 | 0.0 | 0.0 | 0.0 | 49.84 | false | false | + When Loan Pay-off is made on "16 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3747 Scenario: Verify Capitalized Income Amortization validation while run COB a month after Capitalized Income trn - UC1 When Admin sets the business date to "01 January 2024" @@ -6849,7 +6958,7 @@ Feature: Capitalized Income | 31 January 2024 | Capitalized Income Amortization | 17.03 | 0.0 | 17.03 | 0.0 | 0.0 | 0.0 | false | false | When Loan Pay-off is made on "01 February 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3748 Scenario: Verify Capitalized Income Amortization while run COB a month after Capitalized Income with Adjustment trns - UC2 @@ -6888,7 +6997,7 @@ Feature: Capitalized Income | 31 January 2024 | Capitalized Income Amortization | 3.41 | 0.0 | 3.41 | 0.0 | 0.0 | 0.0 | false | false | When Loan Pay-off is made on "01 February 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3749 Scenario: Verify backdated Capitalized Income Amortization while add Capitalised Income trn with a month earlier date - UC3 @@ -6939,7 +7048,7 @@ Feature: Capitalized Income | 01 February 2024 | Capitalized Income Amortization | 17.58 | 0.0 | 17.58 | 0.0 | 0.0 | 0.0 | false | false | When Loan Pay-off is made on "02 February 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3750 Scenario: Verify backdated Capitalized Income Amortization while add Capitalised Income and Adjustment trns with earlier date - UC4 @@ -6992,7 +7101,7 @@ Feature: Capitalized Income | 01 February 2024 | Capitalized Income Amortization | 3.44 | 0.0 | 3.44 | 0.0 | 0.0 | 0.0 | false | false | When Loan Pay-off is made on "02 February 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3751 Scenario: Verify Capitalized Income Amortization while add additional Capitalized Income trn with earlier date - UC5 @@ -7050,7 +7159,7 @@ Feature: Capitalized Income | 01 February 2024 | Capitalized Income Amortization | 17.77 | 0.0 | 17.77 | 0.0 | 0.0 | 0.0 | false | false | When Loan Pay-off is made on "02 February 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3752 Scenario: Verify Capitalized Income Amortization while add additional Capitalized Income trn with earlier date after Adjustment trn - UC6 @@ -7113,7 +7222,7 @@ Feature: Capitalized Income | 01 February 2024 | Capitalized Income Amortization | 17.33 | 0.0 | 17.33 | 0.0 | 0.0 | 0.0 | false | false | When Loan Pay-off is made on "02 February 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3753 Scenario: Verify Capitalized Income Amortization while add additional Capitalized Income with Adjustment trns with earlier date after Adjustment trn - UC7 @@ -7178,7 +7287,7 @@ Feature: Capitalized Income | 01 February 2024 | Capitalized Income Amortization | 3.55 | 0.0 | 3.55 | 0.0 | 0.0 | 0.0 | false | false | When Loan Pay-off is made on "02 February 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3754 Scenario: Verify Capitalized Income Amortization while run COB a month after Capitalized Income with Adjustment trns for multidisbursl loan - UC8 @@ -7217,7 +7326,7 @@ Feature: Capitalized Income | 31 January 2024 | Capitalized Income Amortization | 3.41 | 0.0 | 3.41 | 0.0 | 0.0 | 0.0 | false | false | When Loan Pay-off is made on "01 February 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3755 Scenario: Verify Capitalized Income Amortization while add additional Capitalized Income trn with earlier date for multidisbursl loan - UC9 @@ -7275,7 +7384,7 @@ Feature: Capitalized Income | 01 February 2024 | Capitalized Income Amortization | 17.77 | 0.0 | 17.77 | 0.0 | 0.0 | 0.0 | false | false | When Loan Pay-off is made on "02 February 2024" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3735 Scenario: Verify Capitalized Income business events @@ -7303,6 +7412,9 @@ Feature: Capitalized Income And Admin sets the business date to "05 January 2024" And Admin runs inline COB job for Loan + When Loan Pay-off is made on "05 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3758 Scenario: Verify validation of capitalized income amount with disbursement amount not exceed approved over applied amount for multidisbursal progressive loan - failed scenario When Admin sets the business date to "1 January 2024" @@ -7317,6 +7429,9 @@ Feature: Capitalized Income And Admin successfully disburse the loan on "2 January 2024" with "300" EUR transaction amount Then Capitalized income with payment type "AUTOPAY" on "2 January 2024" is forbidden with amount "300" while exceed approved amount + When Loan Pay-off is made on "02 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3759 Scenario: Verify validation of capitalized income amount with disbursement amount not exceed approved over applied amount for multidisbursal progressive loan - successful scenario When Admin sets the business date to "1 January 2024" @@ -7331,6 +7446,9 @@ Feature: Capitalized Income And Admin successfully disburse the loan on "2 January 2024" with "300" EUR transaction amount And Admin adds capitalized income with "AUTOPAY" payment type to the loan on "02 January 2024" with "200" EUR transaction amount + When Loan Pay-off is made on "02 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3782 Scenario: Verify that Capitalized Income Amortization Adjustment is created when a Capitalized Income Adjustment overpays the loan When Admin sets the business date to "1 January 2024" @@ -7435,6 +7553,9 @@ Feature: Capitalized Income | INCOME | 404000 | Interest Income | 5.26 | | | LIABILITY | 145024 | Deferred Capitalized Income | | 5.26 | + When Admin makes Credit Balance Refund transaction on "03 January 2024" with 96.33 EUR transaction amount + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3899 Scenario: Verify available disbursement amount should consider calculation with capitalized income When Admin sets the business date to "1 January 2024" @@ -7456,6 +7577,9 @@ Feature: Capitalized Income # Available amount = 1000 - 800 - 200 - 0 = 0 Then Loan's available disbursement amount is "0.0" + When Loan Pay-off is made on "02 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3913 Scenario: Verify available disbursement amount calculation with multiple capitalized income transactions When Admin sets the business date to "1 January 2024" @@ -7484,6 +7608,9 @@ Feature: Capitalized Income # Available amount = 2000 - 1400 - 600 - 0 = 0 Then Loan's available disbursement amount is "0.0" + When Loan Pay-off is made on "03 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3914 Scenario: Verify available disbursement amount calculation after capitalized income adjustment When Admin sets the business date to "1 January 2024" @@ -7508,6 +7635,9 @@ Feature: Capitalized Income # Available amount = 1000 - 850 - 150 - 0 = 0 Then Loan's available disbursement amount is "0.0" + When Loan Pay-off is made on "02 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3915 Scenario: Verify available disbursement amount calculation with over applied amount configuration When Admin sets the business date to "1 January 2024" @@ -7530,6 +7660,9 @@ Feature: Capitalized Income # Available amount = 1200 - 900 - 300 - 0 = 0 Then Loan's available disbursement amount is "0.0" + When Loan Pay-off is made on "02 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4005 Scenario: Verify capitalized income transaction creation with classification field set When Admin sets the business date to "1 January 2024" @@ -7567,6 +7700,9 @@ Feature: Capitalized Income And Admin adds capitalized income adjustment with "AUTOPAY" payment type to the loan on "02 January 2024" with "50" EUR transaction amount And Loan Transactions tab has a "Capitalized Income Adjustment" transaction with date "02 January 2024" which has classification code value "capitalized_income_transaction_classification_value" + When Loan Pay-off is made on "02 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4008 Scenario: Verify Capitalized income amortization allocation mappings When Admin sets the business date to "1 January 2024" @@ -7618,6 +7754,9 @@ Feature: Capitalized Income | Date | Type | Amount | | 02 January 2024 | AM | 1.11 | + When Loan Pay-off is made on "03 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4020 Scenario: Verify Capitalized income amortization allocation mappings when capitalized income transaction is reversed When Admin sets the business date to "1 January 2024" @@ -7715,6 +7854,9 @@ Feature: Capitalized Income | 03 January 2024 | AM | 2.22 | | 04 January 2024 | AM | 2.23 | + When Loan Pay-off is made on "05 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4021 Scenario: Verify Capitalized income amortization allocation mappings when capitalized income adjustment occurs When Admin sets the business date to "1 January 2024" @@ -7884,6 +8026,9 @@ Feature: Capitalized Income | 05 January 2024 | AM_ADJ | 0.25 | | 06 January 2024 | AM | 0.43 | + When Loan Pay-off is made on "05 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4041 Scenario: Verify Capitalized Income amortization allocation mapping when already amortized amount is greater than should be after capitalized income adjustment When Admin sets the business date to "1 January 2024" @@ -7963,6 +8108,9 @@ Feature: Capitalized Income | Amount | Amortized Amount | Unrecognized Amount | Adjusted Amount | Charged Off Amount | | 1.0 | 0.3 | 0.0 | 0.7 | 0.0 | + When Loan Pay-off is made on "25 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4042 Scenario: Verify Capitalized Income amortization allocation mapping when after capitalized income adjustment and charge-off When Admin sets the business date to "1 January 2024" @@ -8102,6 +8250,9 @@ Feature: Capitalized Income | Amount | Amortized Amount | Unrecognized Amount | Adjusted Amount | Charged Off Amount | | 1.0 | 0.5 | 0.0 | 0.3 | 0.2 | + When Loan Pay-off is made on "16 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4095 Scenario: Verify GL entries for Capitalized Income Amortization - UC1: Amortization for Capitalized Income with NO classification rule When Admin sets the business date to "01 January 2024" @@ -8123,6 +8274,9 @@ Feature: Capitalized Income | INCOME | 404000 | Interest Income | | 0.55 | | LIABILITY | 145024 | Deferred Capitalized Income | 0.55 | | + When Loan Pay-off is made on "02 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4096 Scenario: Verify GL entries for Capitalized Income Amortization - UC2: Amortization for Capitalized Income with classification rule: pending_bankruptcy When Admin sets the business date to "01 January 2024" @@ -8144,6 +8298,9 @@ Feature: Capitalized Income | INCOME | 744008 | Recoveries | | 0.55 | | LIABILITY | 145024 | Deferred Capitalized Income | 0.55 | | + When Loan Pay-off is made on "02 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4097 Scenario: Verify GL entries for Capitalized Income Amortization - UC3: Amortization for Capitalized Incomes with NO classification and with classification rule: pending_bankruptcy When Admin sets the business date to "01 January 2024" @@ -8177,6 +8334,9 @@ Feature: Capitalized Income | INCOME | 404000 | Interest Income | | 0.55 | | LIABILITY | 145024 | Deferred Capitalized Income | 0.77 | | + When Loan Pay-off is made on "03 January 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4114 Scenario: Verify Capitalized Income journal entries values when backdated new capitalized income with no classification and capitalized income adjustment for existing one with classification occurs on the same day When Admin sets the business date to "01 January 2024" @@ -8266,6 +8426,9 @@ Feature: Capitalized Income | LIABILITY | 145024 | Deferred Capitalized Income | 30.0 | | | INCOME | 744008 | Recoveries | 5.0 | | + When Loan Pay-off is made on "16 April 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4115 Scenario: Verify Capitalized Income journal entries values when backdated new capitalized income and capitalized income adjustment for existing one occurs on the same day, no classification When Admin sets the business date to "01 January 2024" @@ -8353,3 +8516,6 @@ Feature: Capitalized Income | LIABILITY | 145024 | Deferred Capitalized Income | | 5.0 | | LIABILITY | 145024 | Deferred Capitalized Income | 30.0 | | | INCOME | 404000 | Interest Income | 5.0 | | + + When Loan Pay-off is made on "16 April 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met 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 8585adb3e1d..e1b7949997f 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanReAging.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanReAging.feature @@ -47,6 +47,9 @@ Feature: LoanReAging | 20 February 2024 | Re-age | 750.0 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | Then Admin checks that delinquency range is: "NO_DELINQUENCY" and has delinquentDate "" + When Loan Pay-off is made on "20 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3051 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction made by Loan external ID happy path works properly When Admin sets the business date to "01 January 2024" @@ -83,6 +86,9 @@ Feature: LoanReAging | 01 January 2024 | Down Payment | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 750.0 | false | | 20 February 2024 | Re-age | 750.0 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "20 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3052 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction undo works properly When Admin sets the business date to "01 January 2024" @@ -136,6 +142,9 @@ Feature: LoanReAging | 20 February 2024 | Re-age | 750.0 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | true | Then Admin checks that delinquency range is: "RANGE_30" and has delinquentDate "2024-01-19" + When Loan Pay-off is made on "20 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3053 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction works properly when chargeback happens after re-aging When Admin sets the business date to "01 January 2024" @@ -208,6 +217,9 @@ Feature: LoanReAging | 21 February 2024 | Re-age | 750.0 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | | 25 February 2024 | Chargeback | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | + When Loan Pay-off is made on "25 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3054 @AdvancedPaymentAllocation Scenario: Verify Loan re-aging transaction - reverse-replay scenario 1 When Admin sets the business date to "01 January 2024" @@ -244,6 +256,9 @@ Feature: LoanReAging | 01 February 2024 | Repayment | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 500.0 | false | | 27 February 2024 | Re-age | 500.0 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | true | + When Loan Pay-off is made on "27 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3055 @AdvancedPaymentAllocation Scenario: Verify Loan re-aging transaction - reverse-replay scenario 2 When Admin sets the business date to "01 January 2024" @@ -279,6 +294,9 @@ Feature: LoanReAging | 01 January 2024 | Down Payment | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 750.0 | true | | 27 February 2024 | Re-age | 1000.0 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | true | + When Loan Pay-off is made on "27 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3056 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction - chargeback before maturity and prior to re-aging When Admin sets the business date to "01 January 2024" @@ -346,6 +364,9 @@ Feature: LoanReAging | 02 February 2024 | Chargeback | 125.0 | 125.0 | 0.0 | 0.0 | 0.0 | 875.0 | false | | 21 February 2024 | Re-age | 875.0 | 875.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "21 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3057 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction - chargeback after maturity date and prior to re-aging When Admin sets the business date to "01 January 2024" @@ -415,6 +436,9 @@ Feature: LoanReAging | 20 February 2024 | Chargeback | 125.0 | 125.0 | 0.0 | 0.0 | 0.0 | 875.0 | false | | 21 February 2024 | Re-age | 875.0 | 875.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "21 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3058 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction - chargeback after maturity date and prior to re-aging with charge N+1 installment When Admin sets the business date to "01 January 2024" @@ -490,6 +514,9 @@ Feature: LoanReAging | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | | 1125.0 | 0.0 | 0.0 | 20.0 | 1145.0 | 270.0 | 0.0 | 20.0 | 875.0 | + When Loan Pay-off is made on "27 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3059 @AdvancedPaymentAllocation Scenario: Verify Loan re-aging transaction - partial principal payment scenario + undo re-ageing When Admin sets the business date to "01 January 2024" @@ -563,6 +590,9 @@ Feature: LoanReAging | 16 January 2024 | Repayment | 50.0 | 50.0 | 0.0 | 0.0 | 0.0 | 325.0 | false | | 27 February 2024 | Re-age | 325.0 | 325.0 | 0.0 | 0.0 | 0.0 | 0.0 | true | + When Loan Pay-off is made on "29 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3091 @AdvancedPaymentAllocation Scenario: Verify Loan re-age transaction - Event check When Admin sets the business date to "01 January 2024" @@ -582,6 +612,9 @@ Feature: LoanReAging Then LoanDelinquencyRangeChangeBusinessEvent is created Then LoanReAgeBusinessEvent is created + When Loan Pay-off is made on "27 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3107 @AdvancedPaymentAllocation Scenario: Verify Loan re-aging transaction reverse-replay - UC1: undo old repayment When Admin sets the business date to "01 January 2024" @@ -639,6 +672,9 @@ Feature: LoanReAging | 16 January 2024 | Repayment | 125.0 | 125.0 | 0.0 | 0.0 | 0.0 | 250.0 | true | false | | 20 February 2024 | Re-age | 375.0 | 375.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | true | + When Loan Pay-off is made on "25 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3108 @AdvancedPaymentAllocation Scenario: Verify Loan re-aging transaction reverse-replay - UC2: backdated repayment When Admin sets the business date to "01 January 2024" @@ -693,6 +729,9 @@ Feature: LoanReAging | 16 January 2024 | Repayment | 125.0 | 125.0 | 0.0 | 0.0 | 0.0 | 250.0 | false | false | | 20 February 2024 | Re-age | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | true | + When Loan Pay-off is made on "25 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3109 @AdvancedPaymentAllocation Scenario: Verify Loan re-aging transaction reverse-replay - UC3: backdated disbursement When Admin sets the business date to "01 January 2024" @@ -750,6 +789,9 @@ Feature: LoanReAging | 16 January 2024 | Down Payment | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | 450.0 | false | false | | 20 February 2024 | Re-age | 450.0 | 450.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | true | + When Loan Pay-off is made on "25 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C3110 @AdvancedPaymentAllocation Scenario: Verify Loan re-aging transaction reverse-replay - UC4: backdated charge When Admin sets the business date to "01 January 2024" @@ -807,6 +849,9 @@ Feature: LoanReAging | 16 January 2024 | Repayment | 145.0 | 125.0 | 0.0 | 0.0 | 20.0 | 250.0 | false | true | | 20 February 2024 | Re-age | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | true | + When Loan Pay-off is made on "25 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4036 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction made by Loan external ID with undo and additional re-age trn at the same date works properly - UC1 When Admin sets the business date to "01 January 2024" @@ -824,6 +869,9 @@ Feature: LoanReAging | 2 | 15 | 16 January 2024 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | | 3 | 15 | 31 January 2024 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | | 4 | 15 | 15 February 2024 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + Then Loan Repayment schedule 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 | 250.0 | 0.0 | 0.0 | 750.0 | When Admin sets the business date to "20 February 2024" When Admin creates a Loan re-aging transaction by Loan external ID with the following data: | frequencyNumber | frequencyType | startDate | numberOfInstallments | @@ -837,6 +885,9 @@ Feature: LoanReAging | 4 | 15 | 15 February 2024 | 20 February 2024 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | | 5 | 24 | 10 March 2024 | | 375.0 | 375.0 | 0.0 | 0.0 | 0.0 | 375.0 | 0.0 | 0.0 | 0.0 | 375.0 | | 6 | 30 | 09 April 2024 | | 0.0 | 375.0 | 0.0 | 0.0 | 0.0 | 375.0 | 0.0 | 0.0 | 0.0 | 375.0 | + Then Loan Repayment schedule 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 | 250.0 | 0.0 | 0.0 | 750.0 | 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 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | false | @@ -851,6 +902,9 @@ Feature: LoanReAging | 2 | 15 | 16 January 2024 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | | 3 | 15 | 31 January 2024 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | | 4 | 15 | 15 February 2024 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + Then Loan Repayment schedule 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 | 250.0 | 0.0 | 0.0 | 750.0 | 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 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | false | @@ -870,6 +924,9 @@ Feature: LoanReAging | 4 | 15 | 15 February 2024 | 20 February 2024 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | | 5 | 24 | 10 March 2024 | | 375.0 | 375.0 | 0.0 | 0.0 | 0.0 | 375.0 | 0.0 | 0.0 | 0.0 | 375.0 | | 6 | 30 | 09 April 2024 | | 0.0 | 375.0 | 0.0 | 0.0 | 0.0 | 375.0 | 0.0 | 0.0 | 0.0 | 375.0 | + Then Loan Repayment schedule 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 | 250.0 | 0.0 | 0.0 | 750.0 | 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 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | false | @@ -877,6 +934,9 @@ Feature: LoanReAging | 20 February 2024 | Re-age | 750.0 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | true | false | | 20 February 2024 | Re-age | 750.0 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | + When Loan Pay-off is made on "20 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4037 @AdvancedPaymentAllocation Scenario: Verify Loan re-aging transaction - reverse-replay scenario with undo and re-age trn again at the same date - UC2 When Admin sets the business date to "01 January 2024" @@ -938,6 +998,9 @@ Feature: LoanReAging | 27 February 2024 | Re-age | 500.0 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | true | | 27 February 2024 | Re-age | 500.0 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "01 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4038 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction - chargeback before maturity and prior to re-aging - with undo and re-age trn again at the same date - UC3 When Admin sets the business date to "01 January 2024" @@ -954,6 +1017,9 @@ Feature: LoanReAging | 2 | 15 | 16 January 2024 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | | 3 | 15 | 31 January 2024 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | | 4 | 15 | 15 February 2024 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + Then Loan Repayment schedule 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 | When Admin sets the business date to "01 January 2024" And Customer makes "AUTOPAY" repayment on "01 January 2024" with 250 EUR transaction amount Then Loan Repayment schedule has 4 periods, with the following data for periods: @@ -963,6 +1029,9 @@ Feature: LoanReAging | 2 | 15 | 16 January 2024 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | | 3 | 15 | 31 January 2024 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | | 4 | 15 | 15 February 2024 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + Then Loan Repayment schedule 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 | 250.0 | 0.0 | 0.0 | 750.0 | Then Loan Transactions tab has the following data: | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | | 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | @@ -976,14 +1045,14 @@ Feature: LoanReAging | 2 | 15 | 16 January 2024 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | | 3 | 15 | 31 January 2024 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | | 4 | 15 | 15 February 2024 | | 0.0 | 375.0 | 0.0 | 0.0 | 0.0 | 375.0 | 0.0 | 0.0 | 0.0 | 375.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 1125.0 | 0.0 | 0.0 | 0.0 | 1125.0 | 250.0 | 0.0 | 0.0 | 875.0 | Then Loan Transactions tab has the following data: | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | | 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | | 01 January 2024 | Repayment | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 750.0 | false | | 02 February 2024 | Chargeback | 125.0 | 125.0 | 0.0 | 0.0 | 0.0 | 875.0 | false | - Then Loan Repayment schedule has the following data in Total row: - | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | - | 1125.0 | 0.0 | 0.0 | 0.0 | 1125.0 | 250.0 | 0.0 | 0.0 | 875.0 | When Admin sets the business date to "21 February 2024" When Admin creates a Loan re-aging transaction by Loan external ID with the following data: | frequencyNumber | frequencyType | startDate | numberOfInstallments | @@ -1013,15 +1082,15 @@ Feature: LoanReAging | 2 | 15 | 16 January 2024 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | | 3 | 15 | 31 January 2024 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | | 4 | 15 | 15 February 2024 | | 0.0 | 375.0 | 0.0 | 0.0 | 0.0 | 375.0 | 0.0 | 0.0 | 0.0 | 375.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 1125.0 | 0.0 | 0.0 | 0.0 | 1125.0 | 250.0 | 0.0 | 0.0 | 875.0 | Then Loan Transactions tab has the following data: | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | | 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | | 01 January 2024 | Repayment | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 750.0 | false | | 02 February 2024 | Chargeback | 125.0 | 125.0 | 0.0 | 0.0 | 0.0 | 875.0 | false | | 21 February 2024 | Re-age | 875.0 | 875.0 | 0.0 | 0.0 | 0.0 | 0.0 | true | - Then Loan Repayment schedule has the following data in Total row: - | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | - | 1125.0 | 0.0 | 0.0 | 0.0 | 1125.0 | 250.0 | 0.0 | 0.0 | 875.0 | # --- make re-age transaction again --- # When Admin creates a Loan re-aging transaction by Loan external ID with the following data: | frequencyNumber | frequencyType | startDate | numberOfInstallments | @@ -1036,6 +1105,9 @@ Feature: LoanReAging | 5 | 24 | 10 March 2024 | | 583.33 | 291.67 | 0.0 | 0.0 | 0.0 | 291.67 | 0.0 | 0.0 | 0.0 | 291.67 | | 6 | 61 | 10 May 2024 | | 291.66 | 291.67 | 0.0 | 0.0 | 0.0 | 291.67 | 0.0 | 0.0 | 0.0 | 291.67 | | 7 | 61 | 10 July 2024 | | 0.0 | 291.66 | 0.0 | 0.0 | 0.0 | 291.66 | 0.0 | 0.0 | 0.0 | 291.66 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 1125.0 | 0.0 | 0.0 | 0.0 | 1125.0 | 250.0 | 0.0 | 0.0 | 875.0 | Then Loan Transactions tab has the following data: | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | | 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | @@ -1044,6 +1116,9 @@ Feature: LoanReAging | 21 February 2024 | Re-age | 875.0 | 875.0 | 0.0 | 0.0 | 0.0 | 0.0 | true | | 21 February 2024 | Re-age | 875.0 | 875.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "21 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4039 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction - chargeback after maturity date and prior to re-aging with charge N+1 installment - with undo and re-age trn again at the same date - UC4 When Admin sets the business date to "01 January 2024" @@ -1060,6 +1135,9 @@ Feature: LoanReAging | 2 | 15 | 16 January 2024 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | | 3 | 15 | 31 January 2024 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | | 4 | 15 | 15 February 2024 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + Then Loan Repayment schedule 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 | When Admin sets the business date to "01 January 2024" And Customer makes "AUTOPAY" repayment on "01 January 2024" with 250 EUR transaction amount Then Loan Repayment schedule has 4 periods, with the following data for periods: @@ -1069,6 +1147,9 @@ Feature: LoanReAging | 2 | 15 | 16 January 2024 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | | 3 | 15 | 31 January 2024 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | | 4 | 15 | 15 February 2024 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + Then Loan Repayment schedule 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 | 250.0 | 0.0 | 0.0 | 750.0 | Then Loan Transactions tab has the following data: | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | | 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | @@ -1084,14 +1165,14 @@ Feature: LoanReAging | 3 | 15 | 31 January 2024 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | | 4 | 15 | 15 February 2024 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | | 5 | 11 | 26 February 2024 | | 0.0 | 125.0 | 0.0 | 0.0 | 20.0 | 145.0 | 0.0 | 0.0 | 0.0 | 145.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 1125.0 | 0.0 | 0.0 | 20.0 | 1145.0 | 250.0 | 0.0 | 0.0 | 895.0 | Then Loan Transactions tab has the following data: | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | | 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | | 01 January 2024 | Repayment | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 750.0 | false | | 26 February 2024 | Chargeback | 125.0 | 125.0 | 0.0 | 0.0 | 0.0 | 875.0 | false | - Then Loan Repayment schedule has the following data in Total row: - | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | - | 1125.0 | 0.0 | 0.0 | 20.0 | 1145.0 | 250.0 | 0.0 | 0.0 | 895.0 | When Admin sets the business date to "27 February 2024" When Admin makes a charge adjustment for the last "LOAN_NSF_FEE" type charge which is due on "26 February 2024" with 20 EUR transaction amount and externalId "" When Admin creates a Loan re-aging transaction by Loan external ID with the following data: @@ -1108,6 +1189,9 @@ Feature: LoanReAging | 6 | 13 | 10 March 2024 | | 570.0 | 285.0 | 0.0 | 0.0 | 0.0 | 285.0 | 0.0 | 0.0 | 0.0 | 285.0 | | 7 | 61 | 10 May 2024 | | 285.0 | 285.0 | 0.0 | 0.0 | 0.0 | 285.0 | 0.0 | 0.0 | 0.0 | 285.0 | | 8 | 61 | 10 July 2024 | | 0.0 | 285.0 | 0.0 | 0.0 | 0.0 | 285.0 | 0.0 | 0.0 | 0.0 | 285.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 1125.0 | 0.0 | 0.0 | 20.0 | 1145.0 | 270.0 | 0.0 | 20.0 | 875.0 | Then Loan Transactions tab has the following data: | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | | 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | @@ -1115,9 +1199,6 @@ Feature: LoanReAging | 26 February 2024 | Chargeback | 125.0 | 125.0 | 0.0 | 0.0 | 0.0 | 875.0 | false | | 27 February 2024 | Charge Adjustment | 20.0 | 20.0 | 0.0 | 0.0 | 0.0 | 855.0 | false | | 27 February 2024 | Re-age | 855.0 | 855.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | - Then Loan Repayment schedule has the following data in Total row: - | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | - | 1125.0 | 0.0 | 0.0 | 20.0 | 1145.0 | 270.0 | 0.0 | 20.0 | 875.0 | # --- undo re-aging transaction --- # When Admin successfully undo Loan re-aging transaction Then Loan Repayment schedule has 5 periods, with the following data for periods: @@ -1165,6 +1246,9 @@ Feature: LoanReAging | 27 February 2024 | Re-age | 855.0 | 855.0 | 0.0 | 0.0 | 0.0 | 0.0 | true | | 27 February 2024 | Re-age | 855.0 | 855.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "27 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4044 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction - with charge N+1 installment after maturity date prior to re-aging - UC1 When Admin sets the business date to "01 January 2025" @@ -1230,6 +1314,9 @@ Feature: LoanReAging | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | | NSF fee | true | Specified due date | 03 May 2025 | Flat | 10.0 | 0.0 | 0.0 | 10.0 | + When Loan Pay-off is made on "03 May 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4045 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction with backdated repayment and charge - N+1 installment after maturity date prior to re-aging - UC2 When Admin sets the business date to "01 January 2025" @@ -1298,6 +1385,9 @@ Feature: LoanReAging | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | | NSF fee | true | Specified due date | 03 May 2025 | Flat | 10.0 | 0.0 | 0.0 | 10.0 | + When Loan Pay-off is made on "03 May 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4046 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction with downpayment, payoff and charge - N+1 installment after maturity date prior to re-aging - UC3 When Admin sets the business date to "01 January 2025" @@ -1370,6 +1460,9 @@ Feature: LoanReAging | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | | NSF fee | true | Specified due date | 20 March 2025 | Flat | 10.0 | 0.0 | 0.0 | 10.0 | + When Loan Pay-off is made on "20 March 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4047 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction with backdated repayment and chargeback - N+1 installment after maturity date prior to re-aging - UC4 When Admin sets the business date to "01 January 2025" @@ -1434,6 +1527,9 @@ Feature: LoanReAging | 03 May 2025 | Chargeback | 125.0 | 125.0 | 0.0 | 0.0 | 0.0 | 875.0 | false | | 01 April 2025 | Re-age | 750.0 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "03 May 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4048 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction with repayment, chargeback and charge - N+1 installment after maturity date prior to re-aging - UC5 When Admin sets the business date to "01 January 2025" @@ -1505,6 +1601,9 @@ Feature: LoanReAging | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | | NSF fee | true | Specified due date | 03 May 2025 | Flat | 10.0 | 0.0 | 0.0 | 10.0 | + When Loan Pay-off is made on "03 May 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4049 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction with repayment, charge and charge adjustment - N+1 installment after maturity date prior to re-aging - UC6 When Admin sets the business date to "01 January 2025" @@ -1577,6 +1676,9 @@ Feature: LoanReAging | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | | NSF fee | true | Specified due date | 03 May 2025 | Flat | 20.0 | 0.0 | 0.0 | 20.0 | + When Loan Pay-off is made on "03 May 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4050 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction with MIR and charge - N+1 installment after maturity date prior to re-aging - UC7 When Admin sets the business date to "01 January 2025" @@ -1645,13 +1747,16 @@ Feature: LoanReAging | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | | NSF fee | true | Specified due date | 03 May 2025 | Flat | 20.0 | 0.0 | 0.0 | 20.0 | + When Loan Pay-off is made on "03 May 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4051 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction with 2nd disbursement and charge - N+1 installment after maturity date prior to re-aging - UC8 When Admin sets the business date to "01 January 2025" 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_DOWNPAYMENT_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 01 January 2025 | 1000 | 0 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 3 | MONTHS | 1 | MONTHS | 3 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + | LP2_DOWNPAYMENT_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 01 January 2025 | 1000 | 0 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 3 | MONTHS | 1 | MONTHS | 3 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | And Admin successfully approves the loan on "01 January 2025" with "500" amount and expected disbursement date on "01 January 2025" When Admin successfully disburse the loan on "01 January 2025" with "500" EUR transaction amount Then Loan Repayment schedule has 4 periods, with the following data for periods: @@ -1695,7 +1800,7 @@ Feature: LoanReAging # --- add re-aging trn with start date as maturity date --- # When Admin creates a Loan re-aging transaction by Loan external ID with the following data: | frequencyNumber | frequencyType | startDate | numberOfInstallments | - | 1 | WEEKS | 01 April 2025 | 1 | + | 1 | WEEKS | 01 April 2025 | 1 | 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 2025 | | 500.0 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -1718,6 +1823,9 @@ Feature: LoanReAging | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | | NSF fee | true | Specified due date | 01 May 2025 | Flat | 20.0 | 0.0 | 0.0 | 20.0 | + When Loan Pay-off is made on "01 May 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4066 @AdvancedPaymentAllocation Scenario: Verify merging re-aging transaction with N+1 installment in the same bucket(YEARS) When Admin sets the business date to "01 January 2024" @@ -1742,6 +1850,9 @@ Feature: LoanReAging | 5 | 365 | 01 April 2025 | | 25.0 | 25.0 | 0.0 | 100.0 | 0.0 | 125.0 | 0.0 | 0.0 | 0.0 | 125.0 | | 6 | 365 | 01 April 2026 | | 0.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | + When Loan Pay-off is made on "05 April 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4067 @AdvancedPaymentAllocation Scenario: Verify merging re-aging transaction with N+1 installment in the same bucket(MONTHS) When Admin sets the business date to "01 January 2024" @@ -1766,6 +1877,9 @@ Feature: LoanReAging | 5 | 30 | 01 May 2024 | | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | | 6 | 31 | 01 June 2024 | | 0.0 | 25.0 | 0.0 | 100.0 | 0.0 | 125.0 | 0.0 | 0.0 | 0.0 | 125.0 | + When Loan Pay-off is made on "05 April 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4068 @AdvancedPaymentAllocation Scenario: Verify merging re-aging transaction with N+1 installment in the same bucket(WEEKS) When Admin sets the business date to "01 January 2024" @@ -1790,6 +1904,9 @@ Feature: LoanReAging | 5 | 7 | 08 April 2024 | | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | | 6 | 7 | 15 April 2024 | | 0.0 | 25.0 | 0.0 | 100.0 | 0.0 | 125.0 | 0.0 | 0.0 | 0.0 | 125.0 | + When Loan Pay-off is made on "05 April 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4069 @AdvancedPaymentAllocation Scenario: Verify merging re-aging transaction with N+1 installment in the same bucket(DAYS) When Admin sets the business date to "01 January 2024" @@ -1814,6 +1931,9 @@ Feature: LoanReAging | 5 | 1 | 02 April 2024 | | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | | 6 | 1 | 03 April 2024 | | 0.0 | 25.0 | 0.0 | 100.0 | 0.0 | 125.0 | 0.0 | 0.0 | 0.0 | 125.0 | + When Loan Pay-off is made on "05 April 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4070 @AdvancedPaymentAllocation Scenario: Verify re-aging transaction with N+1 installment outside bucket When Admin sets the business date to "01 January 2024" @@ -1839,6 +1959,9 @@ Feature: LoanReAging | 6 | 31 | 01 June 2024 | | 0.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | | 7 | 32 | 03 July 2024 | | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | + When Loan Pay-off is made on "05 April 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4071 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction with backdated repayment and chargeback - N+1 installment after maturity date overlaps with re-aging - UC1 When Admin sets the business date to "01 January 2025" @@ -1907,6 +2030,9 @@ Feature: LoanReAging | 03 May 2025 | Chargeback | 125.0 | 125.0 | 0.0 | 0.0 | 0.0 | 875.0 | false | | 01 April 2025 | Re-age | 750.0 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "03 May 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4072 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction with repayment, chargeback and charge - N+1 installment after maturity date overlaps with re-aging - UC2 When Admin sets the business date to "01 January 2025" @@ -1979,6 +2105,9 @@ Feature: LoanReAging | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | | NSF fee | true | Specified due date | 03 May 2025 | Flat | 10.0 | 0.0 | 0.0 | 10.0 | + When Loan Pay-off is made on "03 May 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4073 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction with repayment, charge and charge adjustment - N+1 installment after maturity date overlaps with re-aging - UC3 When Admin sets the business date to "01 January 2025" @@ -2053,6 +2182,9 @@ Feature: LoanReAging | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | | NSF fee | true | Specified due date | 03 May 2025 | Flat | 20.0 | 0.0 | 0.0 | 20.0 | + When Loan Pay-off is made on "04 May 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4074 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction with MIR and charge - N+1 installment after maturity date overlaps with re-aging - UC4 When Admin sets the business date to "01 January 2025" @@ -2123,6 +2255,9 @@ Feature: LoanReAging | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | | NSF fee | true | Specified due date | 03 May 2025 | Flat | 20.0 | 0.0 | 0.0 | 20.0 | + When Loan Pay-off is made on "03 May 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4055 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction - before maturity date and merges the corresponding normal installments - UC1 When Admin sets the business date to "01 January 2024" @@ -2148,7 +2283,27 @@ Feature: LoanReAging Then Loan Transactions tab has the following data: | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | | 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | + When Admin sets the business date to "09 March 2024" + When Admin creates a Loan re-aging preview by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | + | 1 | MONTHS | 15 March 2024 | 6 | + Then Loan Repayment schedule preview has 9 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 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2024 | 09 March 2024 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 2 | 31 | 01 February 2024 | 09 March 2024 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 29 | 01 March 2024 | 09 March 2024 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 4 | 14 | 15 March 2024 | | 833.33 | 166.67 | 0.0 | 0.0 | 0.0 | 166.67 | 0.0 | 0.0 | 0.0 | 166.67 | + | 5 | 31 | 15 April 2024 | | 666.66 | 166.67 | 0.0 | 0.0 | 0.0 | 166.67 | 0.0 | 0.0 | 0.0 | 166.67 | + | 6 | 30 | 15 May 2024 | | 499.99 | 166.67 | 0.0 | 0.0 | 0.0 | 166.67 | 0.0 | 0.0 | 0.0 | 166.67 | + | 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: + | 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 | + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: | frequencyNumber | frequencyType | startDate | numberOfInstallments | | 1 | MONTHS | 15 March 2024 | 6 | @@ -2172,6 +2327,9 @@ Feature: LoanReAging | 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | | 09 March 2024 | Re-age | 1000.0 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "09 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4056 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction - before maturity date and removes additional normal installments - UC2 When Admin sets the business date to "01 January 2024" @@ -2216,6 +2374,9 @@ Feature: LoanReAging | 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | | 09 March 2024 | Re-age | 1000.0 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "09 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4057 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction with repayment and chargeback - before maturity date and merges the corresponding normal installments - UC3 When Admin sets the business date to "01 January 2025" @@ -2261,6 +2422,24 @@ Feature: LoanReAging | 01 January 2025 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | | 03 February 2025 | Repayment | 167.0 | 167.0 | 0.0 | 0.0 | 0.0 | 833.0 | false | | 03 February 2025 | Chargeback | 100.0 | 100.0 | 0.0 | 0.0 | 0.0 | 933.0 | false | + + When Admin creates a Loan re-aging preview by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | + | 1 | MONTHS | 15 February 2025 | 6 | + Then Loan 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 2025 | | 1000.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 | | 777.0 | 156.0 | 0.0 | 0.0 | 0.0 | 156.0 | 0.0 | 0.0 | 0.0 | 156.0 | + | 3 | 28 | 15 March 2025 | | 621.0 | 156.0 | 0.0 | 0.0 | 0.0 | 156.0 | 0.0 | 0.0 | 0.0 | 156.0 | + | 4 | 31 | 15 April 2025 | | 465.0 | 156.0 | 0.0 | 0.0 | 0.0 | 156.0 | 0.0 | 0.0 | 0.0 | 156.0 | + | 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: + | 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 | + # --- re-age loan on 2nd installment ---# When Admin creates a Loan re-aging transaction by Loan external ID with the following data: | frequencyNumber | frequencyType | startDate | numberOfInstallments | @@ -2285,6 +2464,9 @@ Feature: LoanReAging | 03 February 2025 | Chargeback | 100.0 | 100.0 | 0.0 | 0.0 | 0.0 | 933.0 | false | | 03 February 2025 | Re-age | 933.0 | 933.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "03 February 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4058 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction with repayment and chargeback - before maturity date and removes additional installments - UC4 When Admin sets the business date to "01 January 2025" @@ -2330,6 +2512,19 @@ Feature: LoanReAging | 01 January 2025 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | | 03 February 2025 | Repayment | 167.0 | 167.0 | 0.0 | 0.0 | 0.0 | 833.0 | false | | 03 February 2025 | Chargeback | 100.0 | 100.0 | 0.0 | 0.0 | 0.0 | 933.0 | false | + + When Admin creates a Loan re-aging preview by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | + | 1 | MONTHS | 15 February 2025 | 1 | + Then Loan Repayment schedule preview has 2 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 2025 | | 1000.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: + | 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 | + # --- re-age loan on 2nd installment ---# When Admin creates a Loan re-aging transaction by Loan external ID with the following data: | frequencyNumber | frequencyType | startDate | numberOfInstallments | @@ -2349,6 +2544,9 @@ Feature: LoanReAging | 03 February 2025 | Chargeback | 100.0 | 100.0 | 0.0 | 0.0 | 0.0 | 933.0 | false | | 03 February 2025 | Re-age | 933.0 | 933.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "03 February 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4059 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction with downdpayment - before maturity date and removes additional installments - UC5 When Admin sets the business date to "01 January 2025" @@ -2397,6 +2595,9 @@ Feature: LoanReAging | 01 January 2025 | Down Payment | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 750.0 | false | | 15 February 2025 | Re-age | 750.0 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "15 February 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4060 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction with multiple disbursements - before maturity date and removes additional installments - UC6 When Admin sets the business date to "01 January 2025" @@ -2441,6 +2642,21 @@ Feature: LoanReAging | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | | 01 January 2025 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | | 10 February 2025 | Disbursement | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1500.0 | false | + + When Admin creates a Loan re-aging preview by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | + | 1 | MONTHS | 15 February 2025 | 2 | + Then Loan Repayment schedule preview has 3 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 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2025 | 10 February 2025 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | | | 10 February 2025 | | 500.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: + | 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 | + # --- re-age loan on 2nd installment ---# When Admin creates a Loan re-aging transaction by Loan external ID with the following data: | frequencyNumber | frequencyType | startDate | numberOfInstallments | @@ -2461,6 +2677,9 @@ Feature: LoanReAging | 10 February 2025 | Disbursement | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1500.0 | false | | 10 February 2025 | Re-age | 1500.0 | 1500.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "10 February 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4061 @AdvancedPaymentAllocation Scenario: Verify Loan re-aging transaction at 1st installment with full repayment - before maturity date and merges the corresponding normal installments - UC7 When Admin sets the business date to "01 January 2025" @@ -2526,6 +2745,9 @@ Feature: LoanReAging | 15 January 2025 | Repayment | 167.0 | 167.0 | 0.0 | 0.0 | 0.0 | 833.0 | false | | 15 January 2025 | Re-age | 833.0 | 833.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "15 January 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4062 @AdvancedPaymentAllocation Scenario: Verify Loan re-aging transaction at 1st installment with partial repayment - before maturity date and merges the corresponding normal installments - UC8 When Admin sets the business date to "01 January 2025" @@ -2569,6 +2791,23 @@ Feature: LoanReAging | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | | 01 January 2025 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | | 15 January 2025 | Repayment | 100.0 | 100.0 | 0.0 | 0.0 | 0.0 | 900.0 | false | + + When Admin creates a Loan re-aging preview by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | + | 1 | MONTHS | 16 January 2025 | 6 | + Then Loan 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 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 15 | 16 January 2025 | | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 100.0| 100.0 | 0.0 | 150.0 | + | 2 | 31 | 16 February 2025 | | 600.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | + | 3 | 28 | 16 March 2025 | | 450.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | + | 4 | 31 | 16 April 2025 | | 300.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | + | 5 | 30 | 16 May 2025 | | 150.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | + | 6 | 31 | 16 June 2025 | | 0.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | + Then Loan 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 | 100.0 | 100.0 | 0.0 | 900.0 | + # --- re-age loan on 1st installment ---# When Admin creates a Loan re-aging transaction by Loan external ID with the following data: | frequencyNumber | frequencyType | startDate | numberOfInstallments | @@ -2591,6 +2830,9 @@ Feature: LoanReAging | 15 January 2025 | Repayment | 100.0 | 100.0 | 0.0 | 0.0 | 0.0 | 900.0 | false | | 15 January 2025 | Re-age | 900.0 | 900.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "15 January 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4063 @AdvancedPaymentAllocation Scenario: Verify Loan re-aging transaction at 1st installment with repayment for a few installments - before maturity date and merges the corresponding normal installments - UC9 When Admin sets the business date to "01 January 2025" @@ -2656,6 +2898,9 @@ Feature: LoanReAging | 15 January 2025 | Repayment | 400.0 | 400.0 | 0.0 | 0.0 | 0.0 | 600.0 | false | | 15 January 2025 | Re-age | 600.0 | 600.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "15 January 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4064 @AdvancedPaymentAllocation Scenario: Verify Loan re-aging transaction at 1st installment with MIR - before maturity date and merges the corresponding normal installments - UC10 When Admin sets the business date to "01 January 2025" @@ -2718,7 +2963,10 @@ Feature: LoanReAging | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | | 01 January 2025 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | | 25 January 2025 | Merchant Issued Refund | 300.0 | 300.0 | 0.0 | 0.0 | 0.0 | 700.0 | false | - | 16 January 2025 | Re-age | 1000.0 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + | 16 January 2025 | Re-age | 1000.0 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + + When Loan Pay-off is made on "25 January 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C4065 @AdvancedPaymentAllocation Scenario: Verify Loan re-aging transaction at 1st installment with repayment at last installment - before maturity date and merges the corresponding normal installments - UC11.1 @@ -2763,6 +3011,25 @@ Feature: LoanReAging | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | | 01 January 2025 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | | 15 January 2025 | Repayment | 166.65 | 166.65 | 0.0 | 0.0 | 0.0 | 833.35 | false | + + When Admin creates a Loan re-aging preview by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | + | 1 | MONTHS | 16 January 2025 | 8 | + Then Loan Repayment schedule preview has 8 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 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 15 | 16 January 2025 | | 895.83 | 104.17 | 0.0 | 0.0 | 0.0 | 104.17 | 0.0 | 0.0 | 0.0 | 104.17 | + | 2 | 31 | 16 February 2025 | | 791.66 | 104.17 | 0.0 | 0.0 | 0.0 | 104.17 | 0.0 | 0.0 | 0.0 | 104.17 | + | 3 | 28 | 16 March 2025 | | 687.49 | 104.17 | 0.0 | 0.0 | 0.0 | 104.17 | 0.0 | 0.0 | 0.0 | 104.17 | + | 4 | 31 | 16 April 2025 | | 583.32 | 104.17 | 0.0 | 0.0 | 0.0 | 104.17 | 0.0 | 0.0 | 0.0 | 104.17 | + | 5 | 30 | 16 May 2025 | | 479.15 | 104.17 | 0.0 | 0.0 | 0.0 | 104.17 | 0.0 | 0.0 | 0.0 | 104.17 | + | 6 | 31 | 16 June 2025 | | 208.33 | 270.82 | 0.0 | 0.0 | 0.0 | 270.82 | 166.65 | 166.65 | 0.0 | 104.17 | + | 7 | 30 | 16 July 2025 | | 104.16 | 104.17 | 0.0 | 0.0 | 0.0 | 104.17 | 0.0 | 0.0 | 0.0 | 104.17 | + | 8 | 31 | 16 August 2025 | | 0.0 | 104.16 | 0.0 | 0.0 | 0.0 | 104.16 | 0.0 | 0.0 | 0.0 | 104.16 | + Then Loan 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 | 166.65 | 166.65 | 0.0 | 833.35 | + # --- re-age loan on 1st installment ---# When Admin creates a Loan re-aging transaction by Loan external ID with the following data: | frequencyNumber | frequencyType | startDate | numberOfInstallments | @@ -2787,6 +3054,9 @@ Feature: LoanReAging | 15 January 2025 | Repayment | 166.65 | 166.65 | 0.0 | 0.0 | 0.0 | 833.35 | false | | 15 January 2025 | Re-age | 833.35 | 833.35 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "15 January 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4078 @AdvancedPaymentAllocation Scenario: Verify Loan re-aging transaction at 1st installment with repayment at last installment - before maturity date and merges the corresponding normal installments - UC11.2 When Admin sets the business date to "01 January 2025" @@ -2830,6 +3100,21 @@ Feature: LoanReAging | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | | 01 January 2025 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | | 15 January 2025 | Repayment | 166.65 | 166.65 | 0.0 | 0.0 | 0.0 | 833.35 | false | + + When Admin creates a Loan re-aging preview by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | + | 1 | MONTHS | 16 January 2025 | 4 | + Then Loan Repayment schedule preview has 4 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 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 15 | 16 January 2025 | | 791.66 | 208.34 | 0.0 | 0.0 | 0.0 | 208.34 | 0.0 | 0.0 | 0.0 | 208.34 | + | 2 | 31 | 16 February 2025 | | 583.32 | 208.34 | 0.0 | 0.0 | 0.0 | 208.34 | 0.0 | 0.0 | 0.0 | 208.34 | + | 3 | 28 | 16 March 2025 | | 374.98 | 208.34 | 0.0 | 0.0 | 0.0 | 208.34 | 0.0 | 0.0 | 0.0 | 208.34 | + | 4 | 31 | 16 April 2025 | | 166.65 | 208.33 | 0.0 | 0.0 | 0.0 | 208.33 | 0.0 | 0.0 | 0.0 | 208.33 | + Then Loan Repayment schedule preview has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 833.35 | 0.0 | 0.0 | 0.0 | 833.35 | 0.0 | 0.0 | 0.0 | 833.35 | + # --- re-age loan on 1st installment ---# When Admin creates a Loan re-aging transaction by Loan external ID with the following data: | frequencyNumber | frequencyType | startDate | numberOfInstallments | @@ -2895,6 +3180,9 @@ Feature: LoanReAging | 01 January 2025 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | | 02 January 2025 | Re-age | 1000.0 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "02 January 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4080 @AdvancedPaymentAllocation Scenario: Verify Loan re-aging transaction at 1st installment with charge - before maturity date and removes additional normal installments and not modifies n+1 - UC13 When Admin sets the business date to "01 January 2025" @@ -2925,6 +3213,20 @@ Feature: LoanReAging Then Loan Charges tab has the following data: | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | | NSF fee | true | Specified due date | 01 January 2025 | Flat | 20.0 | 0.0 | 0.0 | 20.0 | + + When Admin creates a Loan re-aging preview by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | + | 1 | MONTHS | 11 January 2025 | 2 | + Then Loan Repayment schedule preview has 3 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 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | 01 January 2025 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | + | 2 | 10 | 11 January 2025 | | 375.0 | 375.0 | 0.0 | 0.0 | 20.0 | 395.0 | 0.0 | 0.0 | 0.0 | 395.0 | + | 3 | 31 | 11 February 2025 | | 0.0 | 375.0 | 0.0 | 0.0 | 0.0 | 375.0 | 0.0 | 0.0 | 0.0 | 375.0 | + Then Loan 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 | 250.0 | 0.0 | 0.0 | 770.0 | + # --- re-age loan on 1st installment ---# When Admin sets the business date to "10 January 2025" When Admin creates a Loan re-aging transaction by Loan external ID with the following data: @@ -2945,6 +3247,9 @@ Feature: LoanReAging | 01 January 2025 | Down Payment | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 750.0 | false | | 10 January 2025 | Re-age | 750.0 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Loan Pay-off is made on "10 January 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4081 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction - can be performed before maturity date and removes n+1 - UC14 When Admin sets the business date to "01 January 2024" @@ -2975,7 +3280,31 @@ Feature: LoanReAging Then Loan Charges tab has the following data: | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | | NSF fee | true | Specified due date | 01 October 2024 | Flat | 20.0 | 0.0 | 0.0 | 20.0 | + When Admin sets the business date to "09 March 2024" + When Admin creates a Loan re-aging preview by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | + | 1 | MONTHS | 15 March 2024 | 10 | + Then Loan Repayment schedule preview has 13 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 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2024 | 09 March 2024 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 2 | 31 | 01 February 2024 | 09 March 2024 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 29 | 01 March 2024 | 09 March 2024 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 4 | 14 | 15 March 2024 | | 900.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | + | 5 | 31 | 15 April 2024 | | 800.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | + | 6 | 30 | 15 May 2024 | | 700.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | + | 7 | 31 | 15 June 2024 | | 600.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | + | 8 | 30 | 15 July 2024 | | 500.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | + | 9 | 31 | 15 August 2024 | | 400.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | + | 10 | 31 | 15 September 2024| | 300.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | + | 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: + | 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 | + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: | frequencyNumber | frequencyType | startDate | numberOfInstallments | | 1 | MONTHS | 15 March 2024 | 10 | @@ -3006,6 +3335,9 @@ Feature: LoanReAging | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | | NSF fee | true | Specified due date | 01 October 2024 | Flat | 20.0 | 0.0 | 0.0 | 20.0 | + When Loan Pay-off is made on "09 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C4082 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging transaction - before maturity date and removes additional normal installments and not modifies n+1 - UC15 When Admin sets the business date to "01 January 2024" @@ -3038,7 +3370,24 @@ Feature: LoanReAging | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | | NSF fee | true | Specified due date | 01 October 2024 | Flat | 20.0 | 0.0 | 0.0 | 20.0 | | NSF fee | true | Specified due date | 01 November 2024| Flat | 30.0 | 0.0 | 0.0 | 30.0 | + When Admin sets the business date to "09 March 2024" + When Admin creates a Loan re-aging preview by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | + | 1 | MONTHS | 15 March 2024 | 2 | + Then Loan 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 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2024 | 09 March 2024 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 2 | 31 | 01 February 2024 | 09 March 2024 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 29 | 01 March 2024 | 09 March 2024 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 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: + | 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 | + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: | frequencyNumber | frequencyType | startDate | numberOfInstallments | | 1 | MONTHS | 15 March 2024 | 2 | @@ -3063,6 +3412,8 @@ Feature: LoanReAging | NSF fee | true | Specified due date | 01 October 2024 | Flat | 20.0 | 0.0 | 0.0 | 20.0 | | NSF fee | true | Specified due date | 01 November 2024 | Flat | 30.0 | 0.0 | 0.0 | 30.0 | + When Loan Pay-off is made on "09 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C4136 @AdvancedPaymentAllocation Scenario: Verify that Loan re-aging with zero outstanding balance is rejected in real-time - UC1 When Admin sets the business date to "01 January 2024" diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanReAgingPreview.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanReAgingPreview.feature new file mode 100644 index 00000000000..eac22ce0ca5 --- /dev/null +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanReAgingPreview.feature @@ -0,0 +1,490 @@ +@LoanReAgingPreviewFeature +Feature: LoanReAgingPreview + + @TestRailId:C4098 + Scenario: Basic verification of the loan re-aging preview schedule + When Admin sets the business date to "01 January 2025" + 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_DOWNPAYMENT_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 01 January 2025 | 1000 | 0 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 3 | MONTHS | 1 | MONTHS | 3 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2025" with "1000" amount and expected disbursement date on "01 January 2025" + When Admin successfully disburse the loan on "01 January 2025" with "1000" EUR transaction amount + Then Loan Repayment schedule has 4 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 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 2 | 31 | 01 February 2025 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 3 | 28 | 01 March 2025 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 4 | 31 | 01 April 2025 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + Then Loan Repayment schedule 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 | + When Admin sets the business date to "15 April 2025" + When Admin creates a Loan re-aging preview by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | + | 1 | MONTHS | 15 April 2025 | 3 | + Then Loan 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 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | 15 April 2025 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 2 | 31 | 01 February 2025 | 15 April 2025 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 28 | 01 March 2025 | 15 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 | 15 April 2025 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 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: + | 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: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 2 | 31 | 01 February 2025 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 3 | 28 | 01 March 2025 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 4 | 31 | 01 April 2025 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + Then Loan Repayment schedule 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 | + + When Loan Pay-off is made on "15 April 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + @TestRailId:C4099 + Scenario: Verify Loan re-aging preview with chargeback + 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_DOWNPAYMENT_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 01 January 2024 | 1000 | 0 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 45 | DAYS | 15 | DAYS | 3 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "1000" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "1000" EUR transaction amount + Then Loan Repayment schedule has 4 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 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2024 | | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 2 | 15 | 16 January 2024 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 3 | 15 | 31 January 2024 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 4 | 15 | 15 February 2024 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + When Admin sets the business date to "01 January 2024" + And Customer makes "AUTOPAY" repayment on "01 January 2024" with 250 EUR transaction amount + Then Loan Repayment schedule has 4 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 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2024 | 01 January 2024 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | + | 2 | 15 | 16 January 2024 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 3 | 15 | 31 January 2024 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 4 | 15 | 15 February 2024 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + When Admin sets the business date to "02 February 2024" + When Admin makes "REPAYMENT_ADJUSTMENT_CHARGEBACK" chargeback with 125 EUR transaction amount + Then Loan Repayment schedule has 4 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 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2024 | 01 January 2024 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | + | 2 | 15 | 16 January 2024 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 3 | 15 | 31 January 2024 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 4 | 15 | 15 February 2024 | | 0.0 | 375.0 | 0.0 | 0.0 | 0.0 | 375.0 | 0.0 | 0.0 | 0.0 | 375.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 1125.0 | 0.0 | 0.0 | 0.0 | 1125.0 | 250.0 | 0.0 | 0.0 | 875.0 | + When Admin sets the business date to "21 February 2024" + When Admin creates a Loan re-aging preview by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | + | 2 | MONTHS | 10 March 2024 | 3 | + Then Loan 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 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2024 | 01 January 2024 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | + | 2 | 15 | 16 January 2024 | 21 February 2024 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 15 | 31 January 2024 | 21 February 2024 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 4 | 15 | 15 February 2024 | 21 February 2024 | 875.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 5 | 24 | 10 March 2024 | | 583.33 | 291.67 | 0.0 | 0.0 | 0.0 | 291.67 | 0.0 | 0.0 | 0.0 | 291.67 | + | 6 | 61 | 10 May 2024 | | 291.66 | 291.67 | 0.0 | 0.0 | 0.0 | 291.67 | 0.0 | 0.0 | 0.0 | 291.67 | + | 7 | 61 | 10 July 2024 | | 0.0 | 291.66 | 0.0 | 0.0 | 0.0 | 291.66 | 0.0 | 0.0 | 0.0 | 291.66 | + And Loan Repayment schedule has 4 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 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2024 | 01 January 2024 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | + | 2 | 15 | 16 January 2024 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 3 | 15 | 31 January 2024 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 4 | 15 | 15 February 2024 | | 0.0 | 375.0 | 0.0 | 0.0 | 0.0 | 375.0 | 0.0 | 0.0 | 0.0 | 375.0 | + And Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 1125.0 | 0.0 | 0.0 | 0.0 | 1125.0 | 250.0 | 0.0 | 0.0 | 875.0 | + + When Loan Pay-off is made on "02 February 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + @TestRailId:C4100 + Scenario: Verify Loan re-aging preview with charge N+1 installment after maturity date + When Admin sets the business date to "01 January 2025" + 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_DOWNPAYMENT_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 01 January 2025 | 1000 | 0 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 3 | MONTHS | 1 | MONTHS | 3 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2025" with "1000" amount and expected disbursement date on "01 January 2025" + When Admin successfully disburse the loan on "01 January 2025" with "1000" EUR transaction amount + When Admin sets the business date to "3 May 2025" + And Admin adds "LOAN_NSF_FEE" due date charge with "3 May 2025" due date and 10 EUR transaction amount + Then Loan Repayment schedule has 5 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 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 2 | 31 | 01 February 2025 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 3 | 28 | 01 March 2025 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 4 | 31 | 01 April 2025 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.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 | + Then Loan Repayment schedule 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 | + When Admin creates a Loan re-aging preview by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | + | 1 | WEEKS | 01 April 2025 | 1 | + Then Loan Repayment schedule preview has 5 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 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | 01 April 2025 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 2 | 31 | 01 February 2025 | 01 April 2025 | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 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: + | 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: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 2 | 31 | 01 February 2025 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 3 | 28 | 01 March 2025 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 4 | 31 | 01 April 2025 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.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 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 | + + When Loan Pay-off is made on "03 May 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + @TestRailId:C4101 + Scenario: Verify Loan re-aging preview with backdated repayment, charge and N+1 installment after maturity date + When Admin sets the business date to "01 January 2025" + 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_DOWNPAYMENT_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 01 January 2025 | 1000 | 0 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 3 | MONTHS | 1 | MONTHS | 3 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2025" with "1000" amount and expected disbursement date on "01 January 2025" + When Admin successfully disburse the loan on "01 January 2025" with "1000" EUR transaction amount + When Admin sets the business date to "3 May 2025" + And Customer makes "AUTOPAY" repayment on "01 March 2025" with 250 EUR transaction amount + And Admin adds "LOAN_NSF_FEE" due date charge with "3 May 2025" due date and 10 EUR transaction amount + Then Loan Repayment schedule has 5 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 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | 01 March 2025 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 | + | 2 | 31 | 01 February 2025 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 3 | 28 | 01 March 2025 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 4 | 31 | 01 April 2025 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.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 | + Then Loan Repayment schedule 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 | + When Admin creates a Loan re-aging preview by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | + | 1 | WEEKS | 01 April 2025 | 1 | + Then Loan Repayment schedule preview has 5 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 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | 01 March 2025 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 | + | 2 | 31 | 01 February 2025 | 01 April 2025 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 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: + | 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: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | 01 March 2025 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 | + | 2 | 31 | 01 February 2025 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 3 | 28 | 01 March 2025 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 4 | 31 | 01 April 2025 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.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 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 | + + When Loan Pay-off is made on "03 May 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + @TestRailId:C4102 + Scenario: Verify Loan re-aging preview with downpayment, payoff and charge - N+1 installment after maturity date + When Admin sets the business date to "01 January 2025" + When Admin creates a client with random data + When Admin set "LP2_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION" 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_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION | 01 January 2025 | 1000 | 0 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 45 | DAYS | 15 | DAYS | 3 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2025" with "1000" amount and expected disbursement date on "01 January 2025" + When Admin successfully disburse the loan on "01 January 2025" with "1000" EUR transaction amount + When Admin sets the business date to "20 March 2025" + When Loan Pay-off is made on "20 March 2025" + And Admin adds "LOAN_NSF_FEE" due date charge with "20 March 2025" due date and 10 EUR transaction amount + Then Loan Repayment schedule has 5 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 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | 01 January 2025 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | + | 2 | 15 | 16 January 2025 | 20 March 2025 | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 | + | 3 | 15 | 31 January 2025 | 20 March 2025 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 | + | 4 | 15 | 15 February 2025 | 20 March 2025 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.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 | + Then Loan Repayment schedule 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 | + When Admin creates a Loan re-aging preview by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | + | 1 | WEEKS | 15 February 2025 | 1 | + Then Loan Repayment schedule preview has 5 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 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | 01 January 2025 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | + | 2 | 15 | 16 January 2025 | 20 March 2025 | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 | + | 3 | 15 | 31 January 2025 | 20 March 2025 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 | + | 4 | 15 | 15 February 2025 | 20 March 2025 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.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: + | 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: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | 01 January 2025 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | + | 2 | 15 | 16 January 2025 | 20 March 2025 | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 | + | 3 | 15 | 31 January 2025 | 20 March 2025 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 | + | 4 | 15 | 15 February 2025 | 20 March 2025 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.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 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 | + + When Loan Pay-off is made on "20 March 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + @TestRailId:C4103 + Scenario: Verify that Loan re-aging preview with repayment, chargeback and charge - N+1 installment after maturity date + When Admin sets the business date to "01 January 2025" + 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_DOWNPAYMENT_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 01 January 2025 | 1000 | 0 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 3 | MONTHS | 1 | MONTHS | 3 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2025" with "1000" amount and expected disbursement date on "01 January 2025" + When Admin successfully disburse the loan on "01 January 2025" with "1000" EUR transaction amount + When Admin sets the business date to "3 May 2025" + And Customer makes "AUTOPAY" repayment on "01 March 2025" with 250 EUR transaction amount + When Admin makes "REPAYMENT_ADJUSTMENT_CHARGEBACK" chargeback with 125 EUR transaction amount + And Admin adds "LOAN_NSF_FEE" due date charge with "3 May 2025" due date and 10 EUR transaction amount + Then Loan Repayment schedule has 5 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 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | 01 March 2025 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 | + | 2 | 31 | 01 February 2025 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 3 | 28 | 01 March 2025 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 4 | 31 | 01 April 2025 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.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 | + Then Loan Repayment schedule 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 | + When Admin creates a Loan re-aging preview by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | + | 1 | WEEKS | 01 April 2025 | 1 | + Then Loan Repayment schedule preview has 5 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 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | 01 March 2025 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 | + | 2 | 31 | 01 February 2025 | 01 April 2025 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 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: + | 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: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | 01 March 2025 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 | + | 2 | 31 | 01 February 2025 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 3 | 28 | 01 March 2025 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 4 | 31 | 01 April 2025 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.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 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 | + + When Loan Pay-off is made on "03 May 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + @TestRailId:C4104 + Scenario: Verify that Loan re-aging preview with repayment, charge and charge adjustment - N+1 installment after maturity date + When Admin sets the business date to "01 January 2025" + 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_DOWNPAYMENT_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 01 January 2025 | 1000 | 0 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 3 | MONTHS | 1 | MONTHS | 3 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2025" with "1000" amount and expected disbursement date on "01 January 2025" + When Admin successfully disburse the loan on "01 January 2025" with "1000" EUR transaction amount + When Admin sets the business date to "3 May 2025" + And Customer makes "AUTOPAY" repayment on "01 March 2025" with 250 EUR transaction amount + And Admin adds "LOAN_NSF_FEE" due date charge with "03 May 2025" due date and 20 EUR transaction amount + When Admin sets the business date to "04 May 2025" + When Admin makes a charge adjustment for the last "LOAN_NSF_FEE" type charge which is due on "03 May 2025" with 20 EUR transaction amount and externalId "" + Then Loan Repayment schedule has 5 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 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | 01 March 2025 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 | + | 2 | 31 | 01 February 2025 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 20.0 | 0.0 | 20.0 | 230.0 | + | 3 | 28 | 01 March 2025 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 4 | 31 | 01 April 2025 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.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 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 | + When Admin creates a Loan re-aging preview by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | + | 1 | WEEKS | 01 April 2025 | 1 | + Then Loan Repayment schedule preview has 5 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 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | 01 March 2025 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 | + | 2 | 31 | 01 February 2025 | 01 April 2025 | 730.0 | 20.0 | 0.0 | 0.0 | 0.0 | 20.0 | 20.0 | 0.0 | 20.0 | 0.0 | + | 3 | 28 | 01 March 2025 | 01 April 2025 | 730.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 | 730.0 | 0.0 | 0.0 | 0.0 | 730.0 | 0.0 | 0.0 | 0.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: + | 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: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | 01 March 2025 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 | + | 2 | 31 | 01 February 2025 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 20.0 | 0.0 | 20.0 | 230.0 | + | 3 | 28 | 01 March 2025 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 4 | 31 | 01 April 2025 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.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 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 | + + When Loan Pay-off is made on "04 May 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + @TestRailId:C4105 + Scenario: Verify that Loan re-aging transaction with MIR and charge - N+1 installment after maturity date + When Admin sets the business date to "01 January 2025" + 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_DOWNPAYMENT_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 01 January 2025 | 1000 | 0 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 3 | MONTHS | 1 | MONTHS | 3 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2025" with "1000" amount and expected disbursement date on "01 January 2025" + And Admin successfully disburse the loan on "01 January 2025" with "1000" EUR transaction amount + And Admin sets the business date to "03 May 2025" + And Admin makes "MERCHANT_ISSUED_REFUND" transaction with "AUTOPAY" payment type on "01 April 2025" with 100 EUR transaction amount + And Admin adds "LOAN_NSF_FEE" due date charge with "03 May 2025" due date and 20 EUR transaction amount + Then Loan Repayment schedule has 5 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 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 100.0 | 0.0 | 100.0 | 150.0 | + | 2 | 31 | 01 February 2025 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 3 | 28 | 01 March 2025 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 4 | 31 | 01 April 2025 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.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 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 | + When Admin creates a Loan re-aging preview by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | + | 1 | WEEKS | 01 April 2025 | 1 | + Then Loan Repayment schedule preview has 5 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 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | 01 April 2025 | 900.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | 100.0 | 0.0 | 100.0 | 0.0 | + | 2 | 31 | 01 February 2025 | 01 April 2025 | 900.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 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: + | 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: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 100.0 | 0.0 | 100.0 | 150.0 | + | 2 | 31 | 01 February 2025 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 3 | 28 | 01 March 2025 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | + | 4 | 31 | 01 April 2025 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.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 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 | + + When Loan Pay-off is made on "03 May 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + @TestRailId:C4106 + Scenario: Verify that Loan re-aging preview with 2nd disbursement and charge - N+1 installment after maturity date + When Admin sets the business date to "01 January 2025" + 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_DOWNPAYMENT_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 01 January 2025 | 1000 | 0 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 3 | MONTHS | 1 | MONTHS | 3 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2025" with "500" amount and expected disbursement date on "01 January 2025" + And Admin successfully disburse the loan on "01 January 2025" with "500" EUR transaction amount + And Admin sets the business date to "01 May 2025" + And Admin successfully disburse the loan on "16 January 2025" with "100" EUR transaction amount + And Admin adds "LOAN_NSF_FEE" due date charge with "01 May 2025" due date and 20 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 2025 | | 500.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | | 375.0 | 125.0 | 0.0 | 0.0 | 0.0 | 125.0 | 0.0 | 0.0 | 0.0 | 125.0 | + | | | 16 January 2025 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 2 | 0 | 16 January 2025 | | 450.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | + | 3 | 31 | 01 February 2025 | | 300.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | + | 4 | 28 | 01 March 2025 | | 150.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | + | 5 | 31 | 01 April 2025 | | 0.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.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 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 | + When Admin creates a Loan re-aging preview by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | + | 1 | WEEKS | 01 April 2025 | 1 | + Then Loan 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 2025 | | 500.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | 01 April 2025 | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | | | 16 January 2025 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 2 | 0 | 16 January 2025 | 01 April 2025 | 600.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 February 2025 | 01 April 2025 | 600.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 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: + | 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: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2025 | | 500.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2025 | | 375.0 | 125.0 | 0.0 | 0.0 | 0.0 | 125.0 | 0.0 | 0.0 | 0.0 | 125.0 | + | | | 16 January 2025 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 2 | 0 | 16 January 2025 | | 450.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | + | 3 | 31 | 01 February 2025 | | 300.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | + | 4 | 28 | 01 March 2025 | | 150.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | + | 5 | 31 | 01 April 2025 | | 0.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.0 | 0.0 | 0.0 | 0.0 | 150.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 | + And Loan Repayment schedule 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 | + + When Loan Pay-off is made on "01 May 2025" + 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-e2e-tests-runner/src/test/resources/features/LoanUpdateApprovedAmount.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanUpdateApprovedAmount.feature index c5e2f5928cd..a93f27b4bf2 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanUpdateApprovedAmount.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanUpdateApprovedAmount.feature @@ -13,7 +13,7 @@ Feature: LoanUpdateApprovedAmount When Admin successfully disburse the loan on "01 January 2025" with "1000" EUR transaction amount When Loan Pay-off is made on "1 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3859 Scenario: Verify update approved amount after undo disbursement for single disb progressive loan - UC3 @@ -30,7 +30,7 @@ Feature: LoanUpdateApprovedAmount When Admin successfully disburse the loan on "01 January 2025" with "600" EUR transaction amount When Loan Pay-off is made on "1 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3860 Scenario: Verify update approved amount with approved over applied amount for progressive multidisbursal loan with percentage overAppliedCalculationType - UC4 @@ -49,7 +49,7 @@ Feature: LoanUpdateApprovedAmount And Admin successfully disburse the loan on "1 January 2025" with "400" EUR transaction amount When Loan Pay-off is made on "1 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3861 Scenario: Verify update approved amount with approved over applied amount and capitalized income for progressive loan with percentage overAppliedCalculationType - UC8_1 @@ -69,7 +69,7 @@ Feature: LoanUpdateApprovedAmount And Admin adds capitalized income with "AUTOPAY" payment type to the loan on "1 January 2025" with "400" EUR transaction amount When Loan Pay-off is made on "1 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3862 Scenario: Verify update approved amount with capitalized income for progressive loan - UC8_2 @@ -86,7 +86,7 @@ Feature: LoanUpdateApprovedAmount And Admin adds capitalized income with "AUTOPAY" payment type to the loan on "1 January 2025" with "200" EUR transaction amount When Loan Pay-off is made on "1 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3863 Scenario: Verify update approved amount with capitalized income for progressive multidisbursal loan - UC8_3 @@ -103,7 +103,7 @@ Feature: LoanUpdateApprovedAmount And Admin successfully disburse the loan on "1 January 2025" with "200" EUR transaction amount When Loan Pay-off is made on "1 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3864 Scenario: Verify update approved amount before disbursement for single disb cumulative loan - UC5_1 @@ -117,7 +117,7 @@ Feature: LoanUpdateApprovedAmount And Admin successfully disburse the loan on "1 January 2025" with "100" EUR transaction amount When Loan Pay-off is made on "1 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3865 Scenario: Verify update approved amount before disbursement for single disb progressive loan - UC5_2 @@ -131,7 +131,7 @@ Feature: LoanUpdateApprovedAmount And Admin successfully disburse the loan on "1 January 2025" with "100" EUR transaction amount When Loan Pay-off is made on "1 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3866 Scenario: Verify approved amount change for progressive multidisbursal loan that doesn't expect tranches - UC6 @@ -159,7 +159,7 @@ Feature: LoanUpdateApprovedAmount Then Update loan approved amount is forbidden with amount "500" due to higher principal amount on loan When Loan Pay-off is made on "1 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3867 Scenario: Verify approved amount change with lower value for progressive multidisbursal loan that expects two tranches - UC7_1 @@ -198,7 +198,7 @@ Feature: LoanUpdateApprovedAmount | 03 January 2025 | Disbursement | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | false | When Loan Pay-off is made on "3 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3868 Scenario: Verify approved amount change with greater value for progressive multidisbursal loan that expects two tranches - UC7_2 @@ -237,4 +237,4 @@ Feature: LoanUpdateApprovedAmount | 03 January 2025 | Disbursement | 600.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1200.0 | false | false | When Loan Pay-off is made on "3 January 2025" - Then Loan's all installments have obligations met \ No newline at end of file + 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-e2e-tests-runner/src/test/resources/features/LoanUpdateAvailableDisbursementAmount.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanUpdateAvailableDisbursementAmount.feature index 96a03be9e8e..41c7b258143 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanUpdateAvailableDisbursementAmount.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanUpdateAvailableDisbursementAmount.feature @@ -15,7 +15,7 @@ Feature: LoanUpdateAvailableDisbursementAmount When Admin successfully disburse the loan on "01 January 2025" with "600" EUR transaction amount When Loan Pay-off is made on "01 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3919 Scenario: Verify update available disbursement amount after undo disbursement for single disb progressive loan - UC3 @@ -32,7 +32,7 @@ Feature: LoanUpdateAvailableDisbursementAmount When Admin successfully disburse the loan on "01 January 2025" with "700" EUR transaction amount When Loan Pay-off is made on "01 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3920 Scenario: Verify update available disbursement amount with approved over applied amount for progressive multidisbursal loan with percentage overAppliedCalculationType - UC4 @@ -53,7 +53,7 @@ Feature: LoanUpdateAvailableDisbursementAmount Then Loan has availableDisbursementAmountWithOverApplied field with value: 0 When Loan Pay-off is made on "01 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3921 Scenario: Verify update available disbursement amount with approved over applied amount and capitalized income for progressive loan with percentage overAppliedCalculationType - UC8_1 @@ -77,7 +77,7 @@ Feature: LoanUpdateAvailableDisbursementAmount Then Loan has availableDisbursementAmountWithOverApplied field with value: 0 When Loan Pay-off is made on "01 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3922 Scenario: Verify update available disbursement amount with capitalized income for progressive loan - UC8_2 @@ -95,7 +95,7 @@ Feature: LoanUpdateAvailableDisbursementAmount And Admin adds capitalized income with "AUTOPAY" payment type to the loan on "1 January 2025" with "150" EUR transaction amount When Loan Pay-off is made on "01 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3923 Scenario: Verify update available disbursement amount with capitalized income for progressive multidisbursal loan - UC8_3 @@ -113,7 +113,7 @@ Feature: LoanUpdateAvailableDisbursementAmount And Admin successfully disburse the loan on "1 January 2025" with "200" EUR transaction amount When Loan Pay-off is made on "01 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3924 Scenario: Verify update available disbursement amount before disbursement for single disb cumulative loan - UC5_1 @@ -128,7 +128,7 @@ Feature: LoanUpdateAvailableDisbursementAmount And Admin successfully disburse the loan on "1 January 2025" with "900" EUR transaction amount When Loan Pay-off is made on "01 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3925 Scenario: Verify update available disbursement amount before disbursement for single disb progressive loan - UC5_2 @@ -143,7 +143,7 @@ Feature: LoanUpdateAvailableDisbursementAmount And Admin successfully disburse the loan on "1 January 2025" with "900" EUR transaction amount When Loan Pay-off is made on "01 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3926 Scenario: Verify available disbursement amount change for progressive multidisbursal loan that doesn't expect tranches - UC6 @@ -172,7 +172,7 @@ Feature: LoanUpdateAvailableDisbursementAmount Then Update loan available disbursement amount is forbidden with amount "500" due to exceed applied amount When Loan Pay-off is made on "01 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3927 Scenario: Verify available disbursement amount change is forbidden with lower value for progressive multidisbursal loan that expects tranches - UC7_1 @@ -216,7 +216,7 @@ Feature: LoanUpdateAvailableDisbursementAmount | 03 January 2025 | Disbursement | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | false | When Loan Pay-off is made on "01 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3928 Scenario: Verify available disbursement amount change with greater value above approved amount for progressive multidisbursal loan that expects tranches - UC7_2 @@ -256,7 +256,7 @@ Feature: LoanUpdateAvailableDisbursementAmount | 03 January 2025 | Disbursement | 700.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1200.0 | false | false | When Loan Pay-off is made on "01 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3929 Scenario: Verify available disbursement amount change with greater value under approved amount for progressive multidisbursal loan that expects tranches - UC7_3 @@ -295,7 +295,7 @@ Feature: LoanUpdateAvailableDisbursementAmount | 03 January 2025 | Disbursement | 350.0 | 0.0 | 0.0 | 0.0 | 0.0 | 950.0 | false | false | When Loan Pay-off is made on "01 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3995 Scenario: Verify update available disbursement amount to zero is forbidden for not approved loan @@ -366,7 +366,7 @@ Feature: LoanUpdateAvailableDisbursementAmount Then Admin fails to disburse the loan on "1 January 2025" with "1" EUR transaction amount due to exceed approved amount When Loan Pay-off is made on "01 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3999 Scenario: Verify availableDisbursementAmountWithOverApplied field calculation @@ -387,7 +387,7 @@ Feature: LoanUpdateAvailableDisbursementAmount And Admin adds capitalized income with "AUTOPAY" payment type to the loan on "1 January 2025" with "150" EUR transaction amount Then Loan has availableDisbursementAmountWithOverApplied field with value: 50 When Loan Pay-off is made on "01 January 2025" - Then Loan's all installments have obligations met + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C4003 Scenario: Verify availableDisbursementAmountWithOverApplied field calculation for progressive multidisbursal loan that expects tranches @@ -430,3 +430,6 @@ Feature: LoanUpdateAvailableDisbursementAmount | 01 January 2025 | Disbursement | 300.0 | 0.0 | 0.0 | 0.0 | 0.0 | 300.0 | false | false | | 02 January 2025 | Disbursement | 200.0 | 0.0 | 0.0 | 0.0 | 0.0 | 500.0 | false | false | | 03 January 2025 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1500.0 | false | false | + + When Loan Pay-off is made on "03 January 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallmentRepository.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallmentRepository.java index 8cbf1748bb6..c7c7af96e24 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallmentRepository.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallmentRepository.java @@ -64,4 +64,12 @@ Collection fetchLoanScheduleDataByDueDateAndObligat @Param("businessDate") LocalDate businessDate, @Param("obligationsMet") boolean obligationsMet, @Param("loanIds") List loanIds); + @Query(""" + SELECT i + FROM LoanRepaymentScheduleInstallment i + WHERE i.loan.id = :loanId + ORDER BY i.loan.id, i.installmentNumber + """) + List findByLoanId(@Param("loanId") Long loanId); + } diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java index e8e2b1d577d..93efbdc760c 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java @@ -2852,7 +2852,7 @@ private void mergeReAgedInstallment(final LoanRepaymentScheduleInstallment targe target.setReAged(true); target.setFromDate(reAgedInstallment.getFromDate()); target.setDueDate(reAgedInstallment.getDueDate()); - target.setPrincipal(reAgedInstallment.getPrincipal().add(MathUtil.nullToZero(target.getPrincipalCompleted()))); + target.setPrincipal(MathUtil.add(reAgedInstallment.getPrincipal(), target.getPrincipalCompleted())); target.setInterestCharged(MathUtil.add(reAgedInstallment.getInterestCharged(), target.getInterestPaid())); target.updateObligationsMet(currency, transactionDate); } @@ -2901,12 +2901,19 @@ private void handleReAge(LoanTransaction loanTransaction, TransactionCtx ctx) { throw new NotImplementedException( "Logic for re-aging when interest bearing loan has interestRecalculation disabled is not implemented"); } else { + final LocalDate startDate = loanTransaction.getLoanReAgeParameter().getStartDate(); + final LocalDate endDate = calculateReAgedInstallmentEndDate(loanTransaction.getLoanReAgeParameter()); + AtomicReference outstandingPrincipalBalance = new AtomicReference<>(Money.zero(currency)); installments.forEach(i -> { - Money principalOutstanding = i.getPrincipalOutstanding(currency); - if (principalOutstanding.isGreaterThanZero()) { - outstandingPrincipalBalance.set(outstandingPrincipalBalance.get().add(principalOutstanding)); - i.addToPrincipal(loanTransaction.getTransactionDate(), principalOutstanding.negated()); + final boolean shouldInclude = !i.isAdditional() || i.getDueDate().isBefore(startDate) + || (!i.getDueDate().isBefore(startDate) && i.getDueDate().isBefore(endDate)); + if (shouldInclude) { + Money principalOutstanding = i.getPrincipalOutstanding(currency); + if (principalOutstanding.isGreaterThanZero()) { + outstandingPrincipalBalance.set(outstandingPrincipalBalance.get().add(principalOutstanding)); + i.addToPrincipal(loanTransaction.getTransactionDate(), principalOutstanding.negated()); + } } }); @@ -3050,17 +3057,22 @@ private void reprocessInstallments(final List }); } + private LocalDate calculateReAgedInstallmentEndDate(final LoanReAgeParameter reAgeParameter) { + return calculateReAgedNextDate(reAgeParameter.getFrequencyType(), reAgeParameter.getStartDate(), + reAgeParameter.getFrequencyNumber(), reAgeParameter.getNumberOfInstallments()); + } + private LocalDate calculateReAgedInstallmentDueDate(final LoanReAgeParameter reAgeParameter, final LocalDate dueDate) { - return calculateReAgedNextDate(reAgeParameter.getFrequencyType(), dueDate, reAgeParameter.getFrequencyNumber()); + return calculateReAgedNextDate(reAgeParameter.getFrequencyType(), dueDate, reAgeParameter.getFrequencyNumber(), 1); } private LocalDate calculateReAgedNextDate(final PeriodFrequencyType frequencyType, final LocalDate dueDate, - final Integer frequencyNumber) { + final Integer frequencyNumber, final Integer numberOfInstallments) { return switch (frequencyType) { - case DAYS -> dueDate.plusDays((long) frequencyNumber); - case WEEKS -> dueDate.plusWeeks((long) frequencyNumber); - case MONTHS -> dueDate.plusMonths((long) frequencyNumber); - case YEARS -> dueDate.plusYears((long) frequencyNumber); + case DAYS -> dueDate.plusDays((long) frequencyNumber * numberOfInstallments); + case WEEKS -> dueDate.plusWeeks((long) frequencyNumber * numberOfInstallments); + case MONTHS -> dueDate.plusMonths((long) frequencyNumber * numberOfInstallments); + case YEARS -> dueDate.plusYears((long) frequencyNumber * numberOfInstallments); default -> throw new UnsupportedOperationException(); }; } 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 ac85e4b43c8..b7a364910ba 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 @@ -18,6 +18,7 @@ */ package org.apache.fineract.portfolio.loanaccount.api; +import com.google.gson.JsonElement; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.enums.ParameterIn; @@ -52,6 +53,7 @@ import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper; import org.apache.fineract.infrastructure.core.api.DateParam; +import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.jersey.Pagination; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.DateFormat; @@ -59,6 +61,7 @@ import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException; import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer; +import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.core.service.CommandParameterUtil; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.ExternalIdFactory; @@ -69,8 +72,10 @@ import org.apache.fineract.portfolio.loanaccount.exception.InvalidLoanTransactionTypeException; import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException; import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionNotFoundException; +import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData; 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.paymenttype.data.PaymentTypeData; import org.apache.fineract.portfolio.paymenttype.service.PaymentTypeReadPlatformService; import org.springframework.data.domain.Page; @@ -101,9 +106,12 @@ public class LoanTransactionsApiResource { private final LoanReadPlatformService loanReadPlatformService; private final ApiRequestParameterHelper apiRequestParameterHelper; private final DefaultToApiJsonSerializer toApiJsonSerializer; + private final DefaultToApiJsonSerializer loanScheduleToApiJsonSerializer; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; private final PaymentTypeReadPlatformService paymentTypeReadPlatformService; private final LoanChargePaidByReadService loanChargePaidByReadService; + private final LoanReAgingService loanReAgingService; + private final FromJsonHelper fromJsonHelper; @GET @Path("{loanId}/transactions/template") @@ -775,4 +783,50 @@ private Long getResolvedLoanIdWithExistsCheck(final Long loanId, final ExternalI throw new IllegalArgumentException("loanId and loanExternalId cannot be both null"); } } + + @POST + @Path("{loanId}/transactions/reage-preview") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Preview Re-Age Schedule", description = "Generates a preview of the re-aged loan schedule based on the provided parameters without creating any transactions or modifying the loan.") + @RequestBody(required = true, content = @Content(schema = @Schema(implementation = LoanTransactionsApiResourceSwagger.PostLoansLoanIdTransactionsRequest.class))) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = LoanScheduleData.class))) }) + public String previewReAgeSchedule(@PathParam("loanId") @Parameter(description = "loanId", required = true) final Long loanId, + @Parameter(hidden = true) final String apiRequestBodyAsJson, @Context final UriInfo uriInfo) { + final LoanScheduleData result = previewReAgeScheduleInternal(loanId, null, apiRequestBodyAsJson); + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + return this.loanScheduleToApiJsonSerializer.serialize(settings, result, new HashSet<>()); + } + + @POST + @Path("external-id/{loanExternalId}/transactions/reage-preview") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Preview Re-Age Schedule", description = "Generates a preview of the re-aged loan schedule based on the provided parameters without creating any transactions or modifying the loan.") + @RequestBody(required = true, content = @Content(schema = @Schema(implementation = LoanTransactionsApiResourceSwagger.PostLoansLoanIdTransactionsRequest.class))) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = LoanScheduleData.class))) }) + public String previewReAgeSchedule( + @PathParam("loanExternalId") @Parameter(description = "loanExternalId", required = true) final String loanExternalId, + @Parameter(hidden = true) final String apiRequestBodyAsJson, @Context final UriInfo uriInfo) { + + final LoanScheduleData result = previewReAgeScheduleInternal(null, loanExternalId, apiRequestBodyAsJson); + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + return this.loanScheduleToApiJsonSerializer.serialize(settings, result, new HashSet<>()); + } + + private LoanScheduleData previewReAgeScheduleInternal(final Long loanId, final String loanExternalIdStr, + final String apiRequestBodyAsJson) { + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); + + final ExternalId loanExternalId = ExternalIdFactory.produce(loanExternalIdStr); + final Long resolvedLoanId = loanId == null ? loanReadPlatformService.getResolvedLoanId(loanExternalId) : loanId; + + final JsonElement parsedCommand = this.fromJsonHelper.parse(apiRequestBodyAsJson); + final JsonCommand command = JsonCommand.from(apiRequestBodyAsJson, parsedCommand, this.fromJsonHelper, null, null, null, null, null, + resolvedLoanId, null, null, null, null, null, null, null, null); + + return loanReAgingService.previewReAge(resolvedLoanId, command); + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/reaging/LoanReAgingCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/reaging/LoanReAgingCommandHandler.java index 7f3778246d9..bb5398cd19d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/reaging/LoanReAgingCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/reaging/LoanReAgingCommandHandler.java @@ -24,7 +24,7 @@ import org.apache.fineract.infrastructure.DataIntegrityErrorHandler; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.loanaccount.service.reaging.LoanReAgingServiceImpl; +import org.apache.fineract.portfolio.loanaccount.service.reaging.LoanReAgingService; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.orm.jpa.JpaSystemException; import org.springframework.stereotype.Service; @@ -34,7 +34,7 @@ @CommandType(entity = "LOAN", action = "REAGE") public class LoanReAgingCommandHandler implements NewCommandSourceHandler { - private final LoanReAgingServiceImpl loanReAgingService; + private final LoanReAgingService loanReAgingService; private final DataIntegrityErrorHandler dataIntegrityErrorHandler; @Override diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/reaging/LoanUndoReAgingCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/reaging/LoanUndoReAgingCommandHandler.java index d66583d2c34..4187c546617 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/reaging/LoanUndoReAgingCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/reaging/LoanUndoReAgingCommandHandler.java @@ -24,7 +24,7 @@ import org.apache.fineract.infrastructure.DataIntegrityErrorHandler; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.loanaccount.service.reaging.LoanReAgingServiceImpl; +import org.apache.fineract.portfolio.loanaccount.service.reaging.LoanReAgingService; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.orm.jpa.JpaSystemException; import org.springframework.stereotype.Service; @@ -34,7 +34,7 @@ @CommandType(entity = "LOAN", action = "UNDO_REAGE") public class LoanUndoReAgingCommandHandler implements NewCommandSourceHandler { - private final LoanReAgingServiceImpl loanReAgingService; + private final LoanReAgingService loanReAgingService; private final DataIntegrityErrorHandler dataIntegrityErrorHandler; @Override diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java index 28d360460d0..3842ec17106 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java @@ -31,8 +31,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; @@ -103,7 +101,6 @@ import org.apache.fineract.portfolio.loanaccount.data.LoanChargePaidByData; import org.apache.fineract.portfolio.loanaccount.data.LoanInterestRecalculationData; import org.apache.fineract.portfolio.loanaccount.data.LoanRepaymentScheduleInstallmentData; -import org.apache.fineract.portfolio.loanaccount.data.LoanSchedulePeriodDataWrapper; import org.apache.fineract.portfolio.loanaccount.data.LoanStatusEnumData; import org.apache.fineract.portfolio.loanaccount.data.LoanSummaryData; import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData; @@ -135,7 +132,6 @@ import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException; import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionNotFoundException; import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData; -import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData; import org.apache.fineract.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; @@ -157,9 +153,7 @@ import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.data.domain.Pageable; import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.RowMapper; -import org.springframework.lang.NonNull; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; @@ -200,6 +194,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa private final LoanBuyDownFeeBalanceRepository loanBuyDownFeeBalanceRepository; private final InterestRefundServiceDelegate interestRefundServiceDelegate; private final LoanMaximumAmountCalculator loanMaximumAmountCalculator; + private final LoanRepaymentScheduleService loanRepaymentScheduleService; @Override public LoanAccountData retrieveOne(final Long loanId) { @@ -279,19 +274,9 @@ public LoanScheduleData retrieveRepaymentSchedule(final Long loanId, final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData, Collection disbursementData, Collection capitalizedIncomeData, boolean isInterestRecalculationEnabled, LoanScheduleType loanScheduleType) { - - try { - this.context.authenticatedUser(); - - final LoanScheduleResultSetExtractor fullResultsetExtractor = new LoanScheduleResultSetExtractor( - repaymentScheduleRelatedLoanData, disbursementData, capitalizedIncomeData, isInterestRecalculationEnabled, - loanScheduleType); - final String sql = "select " + fullResultsetExtractor.schema() + " where ls.loan_id = ? order by ls.loan_id, ls.installment"; - - return this.jdbcTemplate.query(sql, fullResultsetExtractor, loanId); // NOSONAR - } catch (final EmptyResultDataAccessException e) { - throw new LoanNotFoundException(loanId, e); - } + this.context.authenticatedUser(); + return loanRepaymentScheduleService.findLoanScheduleData(loanId, repaymentScheduleRelatedLoanData, disbursementData, + capitalizedIncomeData, isInterestRecalculationEnabled, loanScheduleType); } @Override @@ -1334,373 +1319,6 @@ public OverdueLoanScheduleData mapRow(final ResultSet rs, @SuppressWarnings("unu } } - private static final class LoanScheduleResultSetExtractor implements ResultSetExtractor { - - private final CurrencyData currency; - private final DisbursementData disbursement; - private final BigDecimal totalFeeChargesDueAtDisbursement; - private final Collection disbursementData; - private final Collection capitalizedIncomeData; - private final LoanScheduleType loanScheduleType; - private LocalDate lastDueDate; - private BigDecimal outstandingLoanPrincipalBalance; - private boolean excludePastUnDisbursed; - - LoanScheduleResultSetExtractor(final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData, - Collection disbursementData, Collection capitalizedIncomeData, - boolean isInterestRecalculationEnabled, LoanScheduleType loanScheduleType) { - this.currency = repaymentScheduleRelatedLoanData.getCurrency(); - this.disbursement = repaymentScheduleRelatedLoanData.disbursementData(); - this.capitalizedIncomeData = capitalizedIncomeData; - this.totalFeeChargesDueAtDisbursement = repaymentScheduleRelatedLoanData.getTotalFeeChargesAtDisbursement(); - this.lastDueDate = this.disbursement.disbursementDate(); - this.outstandingLoanPrincipalBalance = this.disbursement.getPrincipal(); - this.disbursementData = disbursementData; - this.excludePastUnDisbursed = isInterestRecalculationEnabled; - this.loanScheduleType = loanScheduleType; - } - - public String schema() { - - return " ls.loan_id as loanId, ls.installment as period, ls.fromdate as fromDate, ls.duedate as dueDate, ls.obligations_met_on_date as obligationsMetOnDate, ls.completed_derived as complete," - + " ls.principal_amount as principalDue, ls.principal_completed_derived as principalPaid, ls.principal_writtenoff_derived as principalWrittenOff, ls.is_additional as isAdditional, " - + " ls.interest_amount as interestDue, ls.interest_completed_derived as interestPaid, ls.interest_waived_derived as interestWaived, ls.interest_writtenoff_derived as interestWrittenOff, " - + " ls.fee_charges_amount as feeChargesDue, ls.fee_charges_completed_derived as feeChargesPaid, ls.fee_charges_waived_derived as feeChargesWaived, ls.fee_charges_writtenoff_derived as feeChargesWrittenOff, " - + " ls.penalty_charges_amount as penaltyChargesDue, ls.penalty_charges_completed_derived as penaltyChargesPaid, ls.penalty_charges_waived_derived as penaltyChargesWaived, " - + " ls.penalty_charges_writtenoff_derived as penaltyChargesWrittenOff, ls.total_paid_in_advance_derived as totalPaidInAdvanceForPeriod, " - + " ls.total_paid_late_derived as totalPaidLateForPeriod, ls.credits_amount as principalCredits, ls.credited_fee as feeCredits, ls.credited_penalty as penaltyCredits, ls.is_down_payment isDownPayment, " - + " ls.accrual_interest_derived as accrualInterest " + " from m_loan_repayment_schedule ls "; - } - - @Override - public LoanScheduleData extractData(@NonNull final ResultSet rs) throws SQLException, DataAccessException { - BigDecimal waivedChargeAmount = BigDecimal.ZERO; - for (DisbursementData disbursementDetail : disbursementData) { - waivedChargeAmount = waivedChargeAmount.add(disbursementDetail.getWaivedChargeAmount()); - } - final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod( - this.disbursement.disbursementDate(), this.disbursement.getPrincipal(), this.totalFeeChargesDueAtDisbursement, - this.disbursement.isDisbursed()); - - final List periods = new ArrayList<>(); - final MonetaryCurrency monCurrency = new MonetaryCurrency(this.currency.getCode(), this.currency.getDecimalPlaces(), - this.currency.getInMultiplesOf()); - BigDecimal totalPrincipalDisbursed = BigDecimal.ZERO; - BigDecimal disbursementChargeAmount = this.totalFeeChargesDueAtDisbursement; - if (disbursementData.isEmpty()) { - periods.add(disbursementPeriod); - totalPrincipalDisbursed = Money.of(monCurrency, this.disbursement.getPrincipal()).getAmount(); - } else { - if (!this.disbursement.isDisbursed()) { - excludePastUnDisbursed = false; - } - for (DisbursementData data : disbursementData) { - if (data.getChargeAmount() != null) { - disbursementChargeAmount = disbursementChargeAmount.subtract(data.getChargeAmount()); - } - } - this.outstandingLoanPrincipalBalance = BigDecimal.ZERO; - } - - Money totalPrincipalExpected = Money.zero(monCurrency); - Money totalPrincipalPaid = Money.zero(monCurrency); - Money totalInterestCharged = Money.zero(monCurrency); - Money totalFeeChargesCharged = Money.zero(monCurrency); - Money totalPenaltyChargesCharged = Money.zero(monCurrency); - Money totalWaived = Money.zero(monCurrency); - Money totalWrittenOff = Money.zero(monCurrency); - Money totalRepaymentExpected = Money.zero(monCurrency); - Money totalRepayment = Money.zero(monCurrency); - Money totalPaidInAdvance = Money.zero(monCurrency); - Money totalPaidLate = Money.zero(monCurrency); - Money totalOutstanding = Money.zero(monCurrency); - Money totalCredits = Money.zero(monCurrency); - - // update totals with details of fees charged during disbursement - totalFeeChargesCharged = totalFeeChargesCharged.plus(disbursementPeriod.getFeeChargesDue().subtract(waivedChargeAmount)); - totalRepaymentExpected = totalRepaymentExpected.plus(disbursementPeriod.getFeeChargesDue()).minus(waivedChargeAmount); - totalRepayment = totalRepayment.plus(disbursementPeriod.getFeeChargesPaid()).minus(waivedChargeAmount); - totalOutstanding = totalOutstanding.plus(disbursementPeriod.getFeeChargesDue()).minus(disbursementPeriod.getFeeChargesPaid()); - - Integer loanTermInDays = 0; - Set disbursementPeriodIds = new HashSet<>(); - while (rs.next()) { - final Integer period = JdbcSupport.getInteger(rs, "period"); - LocalDate fromDate = JdbcSupport.getLocalDate(rs, "fromDate"); - final LocalDate dueDate = JdbcSupport.getLocalDate(rs, "dueDate"); - final LocalDate obligationsMetOnDate = JdbcSupport.getLocalDate(rs, "obligationsMetOnDate"); - final boolean complete = rs.getBoolean("complete"); - - List combinedDataList = new ArrayList<>(); - combinedDataList.addAll( - collectEligibleDisbursementData(loanScheduleType, disbursementData, fromDate, dueDate, disbursementPeriodIds)); - combinedDataList.addAll(collectEligibleCapitalizedIncomeData(fromDate, dueDate, disbursementPeriodIds)); - combinedDataList.sort(this::sortPeriodDataHolders); - fillLoanSchedulePeriodData(periods, combinedDataList, disbursementChargeAmount, waivedChargeAmount); - - BigDecimal disbursedAmount = calculateDisbursedAmount(combinedDataList); - - // Add the Charge back or Credits to the initial amount to avoid negative balance - final BigDecimal principalCredits = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalCredits"); - final BigDecimal feeCredits = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeCredits"); - final BigDecimal penaltyCredits = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyCredits"); - final BigDecimal credits = principalCredits.add(feeCredits).add(penaltyCredits); - this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(principalCredits); - - totalPrincipalDisbursed = totalPrincipalDisbursed.add(disbursedAmount); - - Integer daysInPeriod = 0; - if (fromDate != null) { - daysInPeriod = DateUtils.getExactDifferenceInDays(fromDate, dueDate); - loanTermInDays = loanTermInDays + daysInPeriod; - } - - final BigDecimal principalDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalDue"); - totalPrincipalExpected = totalPrincipalExpected.plus(principalDue); - final BigDecimal principalPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalPaid"); - totalPrincipalPaid = totalPrincipalPaid.plus(principalPaid); - final BigDecimal principalWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principalWrittenOff"); - - final BigDecimal principalOutstanding = principalDue.subtract(principalPaid).subtract(principalWrittenOff); - - final BigDecimal interestExpectedDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestDue"); - totalInterestCharged = totalInterestCharged.plus(interestExpectedDue); - final BigDecimal interestPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestPaid"); - final BigDecimal interestWaived = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestWaived"); - final BigDecimal interestWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interestWrittenOff"); - final BigDecimal accrualInterest = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "accrualInterest"); - - final BigDecimal interestActualDue = interestExpectedDue.subtract(interestWaived).subtract(interestWrittenOff); - final BigDecimal interestOutstanding = interestActualDue.subtract(interestPaid); - - final BigDecimal feeChargesExpectedDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesDue"); - totalFeeChargesCharged = totalFeeChargesCharged.plus(feeChargesExpectedDue); - final BigDecimal feeChargesPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesPaid"); - final BigDecimal feeChargesWaived = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesWaived"); - final BigDecimal feeChargesWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "feeChargesWrittenOff"); - - final BigDecimal feeChargesActualDue = feeChargesExpectedDue.subtract(feeChargesWaived).subtract(feeChargesWrittenOff); - final BigDecimal feeChargesOutstanding = feeChargesActualDue.subtract(feeChargesPaid); - - final BigDecimal penaltyChargesExpectedDue = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyChargesDue"); - totalPenaltyChargesCharged = totalPenaltyChargesCharged.plus(penaltyChargesExpectedDue); - final BigDecimal penaltyChargesPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyChargesPaid"); - final BigDecimal penaltyChargesWaived = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyChargesWaived"); - final BigDecimal penaltyChargesWrittenOff = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penaltyChargesWrittenOff"); - - final BigDecimal totalPaidInAdvanceForPeriod = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, - "totalPaidInAdvanceForPeriod"); - final BigDecimal totalPaidLateForPeriod = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "totalPaidLateForPeriod"); - - final BigDecimal penaltyChargesActualDue = penaltyChargesExpectedDue.subtract(penaltyChargesWaived) - .subtract(penaltyChargesWrittenOff); - final BigDecimal penaltyChargesOutstanding = penaltyChargesActualDue.subtract(penaltyChargesPaid); - - final BigDecimal totalExpectedCostOfLoanForPeriod = interestExpectedDue.add(feeChargesExpectedDue) - .add(penaltyChargesExpectedDue); - - final BigDecimal totalDueForPeriod = principalDue.add(totalExpectedCostOfLoanForPeriod); - final BigDecimal totalPaidForPeriod = principalPaid.add(interestPaid).add(feeChargesPaid).add(penaltyChargesPaid); - final BigDecimal totalWaivedForPeriod = interestWaived.add(feeChargesWaived).add(penaltyChargesWaived); - totalWaived = totalWaived.plus(totalWaivedForPeriod); - final BigDecimal totalWrittenOffForPeriod = principalWrittenOff.add(interestWrittenOff).add(feeChargesWrittenOff) - .add(penaltyChargesWrittenOff); - totalWrittenOff = totalWrittenOff.plus(totalWrittenOffForPeriod); - - final BigDecimal totalOutstandingForPeriod = principalOutstanding.add(interestOutstanding).add(feeChargesOutstanding) - .add(penaltyChargesOutstanding); - - totalRepaymentExpected = totalRepaymentExpected.plus(totalDueForPeriod); - totalRepayment = totalRepayment.plus(totalPaidForPeriod); - totalPaidInAdvance = totalPaidInAdvance.plus(totalPaidInAdvanceForPeriod); - totalPaidLate = totalPaidLate.plus(totalPaidLateForPeriod); - totalOutstanding = totalOutstanding.plus(totalOutstandingForPeriod); - totalCredits = totalCredits.add(credits); - - if (fromDate == null) { - fromDate = this.lastDueDate; - } - - BigDecimal outstandingPrincipalBalanceOfLoan = this.outstandingLoanPrincipalBalance.subtract(principalDue); - - // update based on current period values - this.lastDueDate = dueDate; - this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.subtract(principalDue); - - final boolean isDownPayment = rs.getBoolean("isDownPayment"); - - LoanSchedulePeriodData periodData; - - periodData = LoanSchedulePeriodData.periodWithPayments(period, fromDate, dueDate, obligationsMetOnDate, complete, - principalDue, principalPaid, principalWrittenOff, principalOutstanding, outstandingPrincipalBalanceOfLoan, - interestExpectedDue, interestPaid, interestWaived, interestWrittenOff, interestOutstanding, feeChargesExpectedDue, - feeChargesPaid, feeChargesWaived, feeChargesWrittenOff, feeChargesOutstanding, penaltyChargesExpectedDue, - penaltyChargesPaid, penaltyChargesWaived, penaltyChargesWrittenOff, penaltyChargesOutstanding, totalPaidForPeriod, - totalPaidInAdvanceForPeriod, totalPaidLateForPeriod, totalWaivedForPeriod, totalWrittenOffForPeriod, credits, - isDownPayment, accrualInterest); - - periods.add(periodData); - } - - return new LoanScheduleData(this.currency, periods, loanTermInDays, totalPrincipalDisbursed, totalPrincipalExpected.getAmount(), - totalPrincipalPaid.getAmount(), totalInterestCharged.getAmount(), totalFeeChargesCharged.getAmount(), - totalPenaltyChargesCharged.getAmount(), totalWaived.getAmount(), totalWrittenOff.getAmount(), - totalRepaymentExpected.getAmount(), totalRepayment.getAmount(), totalPaidInAdvance.getAmount(), - totalPaidLate.getAmount(), totalOutstanding.getAmount(), totalCredits.getAmount()); - } - - private List collectEligibleDisbursementData(LoanScheduleType loanScheduleType, - Collection disbursementData, LocalDate fromDate, LocalDate dueDate, Set disbursementPeriodIds) { - List disbursementDataList = new ArrayList<>(); - - boolean hasMultipleTranchesOnSameDate = hasMultipleTranchesOnSameDate(disbursementData); - - if (hasMultipleTranchesOnSameDate) { - Map> disbursementsByDate = new HashMap<>(); - - for (final DisbursementData data : disbursementData) { - boolean isDueForDisbursement = data.isDueForDisbursement(loanScheduleType, fromDate, dueDate); - boolean isEligible = ((fromDate.equals(this.disbursement.disbursementDate()) - && data.disbursementDate().equals(fromDate)) - || (fromDate.equals(dueDate) && data.disbursementDate().equals(fromDate)) - || canAddDisbursementData(data, isDueForDisbursement, excludePastUnDisbursed)) - && !disbursementPeriodIds.contains(data.getId()); - - if (isEligible) { - disbursementsByDate.computeIfAbsent(data.disbursementDate(), k -> new ArrayList<>()).add(data); - disbursementPeriodIds.add(data.getId()); - } - } - - for (Map.Entry> entry : disbursementsByDate.entrySet()) { - List sameDateDisbursements = entry.getValue(); - - if (sameDateDisbursements.size() > 1) { - List disbursedTranches = sameDateDisbursements.stream().filter(DisbursementData::isDisbursed) - .collect(Collectors.toList()); - - if (!disbursedTranches.isEmpty()) { - for (DisbursementData data : disbursedTranches) { - disbursementDataList.add(new LoanSchedulePeriodDataWrapper(data, data.disbursementDate(), true)); - } - } else { - for (DisbursementData data : sameDateDisbursements) { - disbursementDataList.add(new LoanSchedulePeriodDataWrapper(data, data.disbursementDate(), true)); - } - } - } else { - DisbursementData data = sameDateDisbursements.get(0); - disbursementDataList.add(new LoanSchedulePeriodDataWrapper(data, data.disbursementDate(), true)); - } - } - } else { - for (final DisbursementData data : disbursementData) { - boolean isDueForDisbursement = data.isDueForDisbursement(loanScheduleType, fromDate, dueDate); - boolean isEligible = ((fromDate.equals(this.disbursement.disbursementDate()) - && data.disbursementDate().equals(fromDate)) - || (fromDate.equals(dueDate) && data.disbursementDate().equals(fromDate)) - || canAddDisbursementData(data, isDueForDisbursement, excludePastUnDisbursed)) - && !disbursementPeriodIds.contains(data.getId()); - - if (isEligible) { - disbursementDataList.add(new LoanSchedulePeriodDataWrapper(data, data.disbursementDate(), true)); - disbursementPeriodIds.add(data.getId()); - } - } - } - - return disbursementDataList; - } - - private boolean hasMultipleTranchesOnSameDate(Collection disbursementData) { - if (disbursementData == null || disbursementData.size() <= 1) { - return false; - } - return disbursementData.stream().collect(Collectors.groupingBy(DisbursementData::disbursementDate, Collectors.counting())) - .values().stream().anyMatch(count -> count > 1); - } - - private List collectEligibleCapitalizedIncomeData(LocalDate fromDate, LocalDate dueDate, - Set disbursementPeriodIds) { - List capitalizedIncomeDataList = new ArrayList<>(); - // Collect eligible capitalized income data - for (LoanTransactionRepaymentPeriodData data : capitalizedIncomeData) { - boolean isEligible = canAddCapitalizedIncomeData(data, fromDate, dueDate) - && !disbursementPeriodIds.contains(data.getTransactionId()); - - if (isEligible) { - capitalizedIncomeDataList.add(new LoanSchedulePeriodDataWrapper(data, data.getDate(), false)); - disbursementPeriodIds.add(data.getTransactionId()); - } - } - return capitalizedIncomeDataList; - } - - private void fillLoanSchedulePeriodData(List periods, List combinedDataList, - BigDecimal disbursementChargeAmount, BigDecimal waivedChargeAmount) { - // Process all collected data in chronological order - for (LoanSchedulePeriodDataWrapper dataItem : combinedDataList) { - LoanSchedulePeriodData periodData; - if (dataItem.isDisbursement()) { - // Process disbursement data - DisbursementData data = (DisbursementData) dataItem.getData(); - periodData = createLoanSchedulePeriodData(data, disbursementChargeAmount, waivedChargeAmount); - } else { - // Process capitalized income data - LoanTransactionRepaymentPeriodData data = (LoanTransactionRepaymentPeriodData) dataItem.getData(); - periodData = createLoanSchedulePeriodData(data); - } - - // Common processing for both data types - periods.add(periodData); - this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(periodData.getPrincipalDisbursed()); - } - } - - private BigDecimal calculateDisbursedAmount(List combinedDataList) { - BigDecimal disbursedAmount = BigDecimal.ZERO; - for (LoanSchedulePeriodDataWrapper dataItem : combinedDataList) { - if (dataItem.isDisbursement()) { - DisbursementData data = (DisbursementData) dataItem.getData(); - disbursedAmount = disbursedAmount.add(data.getPrincipal()); - } - } - return disbursedAmount; - } - - private int sortPeriodDataHolders(LoanSchedulePeriodDataWrapper item1, LoanSchedulePeriodDataWrapper item2) { - int dateComparison = item1.getDate().compareTo(item2.getDate()); - if (dateComparison == 0 && item1.isDisbursement() != item2.isDisbursement()) { - // If dates are equal, prioritize disbursement data - return item1.isDisbursement() ? -1 : 1; - } - return dateComparison; - } - - private LoanSchedulePeriodData createLoanSchedulePeriodData(final DisbursementData data, BigDecimal disbursementChargeAmount, - BigDecimal waivedChargeAmount) { - BigDecimal chargeAmount = data.getChargeAmount() == null ? disbursementChargeAmount - : disbursementChargeAmount.add(data.getChargeAmount()).subtract(waivedChargeAmount); - return LoanSchedulePeriodData.disbursementOnlyPeriod(data.disbursementDate(), data.getPrincipal(), chargeAmount, - data.isDisbursed()); - } - - private LoanSchedulePeriodData createLoanSchedulePeriodData(final LoanTransactionRepaymentPeriodData data) { - BigDecimal feeCharges = Objects.isNull(data.getFeeChargesPortion()) ? BigDecimal.ZERO : data.getFeeChargesPortion(); - return LoanSchedulePeriodData.disbursementOnlyPeriod(data.getDate(), data.getAmount(), feeCharges, !data.isReversed()); - } - - private boolean canAddDisbursementData(DisbursementData data, boolean isDueForDisbursement, boolean excludePastUnDisbursed) { - return (!excludePastUnDisbursed || data.isDisbursed() || !DateUtils.isBeforeBusinessDate(data.disbursementDate())) - && isDueForDisbursement; - } - - private boolean canAddCapitalizedIncomeData(LoanTransactionRepaymentPeriodData data, LocalDate fromDate, LocalDate dueDate) { - return !data.isReversed() && DateUtils.isDateInRangeFromInclusiveToExclusive(fromDate, dueDate, data.getDate()); - } - - } - private static final class LoanTransactionsMapper implements RowMapper { private final DatabaseSpecificSQLGenerator sqlGenerator; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanRepaymentScheduleService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanRepaymentScheduleService.java new file mode 100644 index 00000000000..d39d0515ef0 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanRepaymentScheduleService.java @@ -0,0 +1,418 @@ +/** + * 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.service; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.infrastructure.core.service.DateUtils; +import org.apache.fineract.organisation.monetary.data.CurrencyData; +import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; +import org.apache.fineract.organisation.monetary.domain.Money; +import org.apache.fineract.portfolio.loanaccount.data.DisbursementData; +import org.apache.fineract.portfolio.loanaccount.data.LoanSchedulePeriodDataWrapper; +import org.apache.fineract.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository; +import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepaymentPeriodData; +import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData; +import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData; +import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class LoanRepaymentScheduleService { + + private final LoanRepaymentScheduleInstallmentRepository loanRepaymentScheduleInstallmentRepository; + + public LoanScheduleData findLoanScheduleData(final Long loanId, final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData, + Collection disbursementData, Collection capitalizedIncomeData, + boolean isInterestRecalculationEnabled, LoanScheduleType loanScheduleType) { + final List installments = this.loanRepaymentScheduleInstallmentRepository.findByLoanId(loanId); + + return extractLoanScheduleData(installments, repaymentScheduleRelatedLoanData, disbursementData, capitalizedIncomeData, + isInterestRecalculationEnabled, loanScheduleType); + } + + public LoanScheduleData extractLoanScheduleData(final List installments, + final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData, Collection disbursementData, + Collection capitalizedIncomeData, boolean isInterestRecalculationEnabled, + LoanScheduleType loanScheduleType) { + + final CurrencyData currency = repaymentScheduleRelatedLoanData.getCurrency(); + final DisbursementData disbursement = repaymentScheduleRelatedLoanData.disbursementData(); + final BigDecimal totalFeeChargesDueAtDisbursement = repaymentScheduleRelatedLoanData.getTotalFeeChargesAtDisbursement(); + LocalDate lastDueDate = disbursement.disbursementDate(); + BigDecimal outstandingLoanPrincipalBalance = disbursement.getPrincipal(); + boolean excludePastUnDisbursed = isInterestRecalculationEnabled; + + BigDecimal waivedChargeAmount = BigDecimal.ZERO; + for (DisbursementData disbursementDetail : disbursementData) { + waivedChargeAmount = waivedChargeAmount.add(disbursementDetail.getWaivedChargeAmount()); + } + final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod(disbursement.disbursementDate(), + disbursement.getPrincipal(), totalFeeChargesDueAtDisbursement, disbursement.isDisbursed()); + + final List periods = new ArrayList<>(); + final MonetaryCurrency monCurrency = new MonetaryCurrency(currency.getCode(), currency.getDecimalPlaces(), + currency.getInMultiplesOf()); + BigDecimal totalPrincipalDisbursed = BigDecimal.ZERO; + BigDecimal disbursementChargeAmount = totalFeeChargesDueAtDisbursement; + if (disbursementData.isEmpty()) { + periods.add(disbursementPeriod); + totalPrincipalDisbursed = Money.of(monCurrency, disbursement.getPrincipal()).getAmount(); + } else { + if (!disbursement.isDisbursed()) { + excludePastUnDisbursed = false; + } + for (DisbursementData data : disbursementData) { + if (data.getChargeAmount() != null) { + disbursementChargeAmount = disbursementChargeAmount.subtract(data.getChargeAmount()); + } + } + outstandingLoanPrincipalBalance = BigDecimal.ZERO; + } + + Money totalPrincipalExpected = Money.zero(monCurrency); + Money totalPrincipalPaid = Money.zero(monCurrency); + Money totalInterestCharged = Money.zero(monCurrency); + Money totalFeeChargesCharged = Money.zero(monCurrency); + Money totalPenaltyChargesCharged = Money.zero(monCurrency); + Money totalWaived = Money.zero(monCurrency); + Money totalWrittenOff = Money.zero(monCurrency); + Money totalRepaymentExpected = Money.zero(monCurrency); + Money totalRepayment = Money.zero(monCurrency); + Money totalPaidInAdvance = Money.zero(monCurrency); + Money totalPaidLate = Money.zero(monCurrency); + Money totalOutstanding = Money.zero(monCurrency); + Money totalCredits = Money.zero(monCurrency); + + // update totals with details of fees charged during disbursement + totalFeeChargesCharged = totalFeeChargesCharged.plus(disbursementPeriod.getFeeChargesDue().subtract(waivedChargeAmount)); + totalRepaymentExpected = totalRepaymentExpected.plus(disbursementPeriod.getFeeChargesDue()).minus(waivedChargeAmount); + totalRepayment = totalRepayment.plus(disbursementPeriod.getFeeChargesPaid()).minus(waivedChargeAmount); + totalOutstanding = totalOutstanding.plus(disbursementPeriod.getFeeChargesDue()).minus(disbursementPeriod.getFeeChargesPaid()); + + Integer loanTermInDays = 0; + Set disbursementPeriodIds = new HashSet<>(); + + for (LoanRepaymentScheduleInstallment installment : installments) { + final Integer period = installment.getInstallmentNumber(); + LocalDate fromDate = installment.getFromDate(); + final LocalDate dueDate = installment.getDueDate(); + final LocalDate obligationsMetOnDate = installment.getObligationsMetOnDate(); + final boolean complete = installment.isObligationsMet(); + + List combinedDataList = new ArrayList<>(); + combinedDataList.addAll(collectEligibleDisbursementData(loanScheduleType, disbursementData, fromDate, dueDate, + disbursementPeriodIds, disbursement, excludePastUnDisbursed)); + combinedDataList.addAll(collectEligibleCapitalizedIncomeData(capitalizedIncomeData, fromDate, dueDate, disbursementPeriodIds)); + combinedDataList.sort(this::sortPeriodDataHolders); + outstandingLoanPrincipalBalance = fillLoanSchedulePeriodData(periods, combinedDataList, disbursementChargeAmount, + waivedChargeAmount, outstandingLoanPrincipalBalance); + + BigDecimal disbursedAmount = calculateDisbursedAmount(combinedDataList); + + // Add the Charge back or Credits to the initial amount to avoid negative balance + final BigDecimal principalCredits = installment.getCreditedPrincipal() != null ? installment.getCreditedPrincipal() + : BigDecimal.ZERO; + final BigDecimal feeCredits = installment.getCreditedFee() != null ? installment.getCreditedFee() : BigDecimal.ZERO; + final BigDecimal penaltyCredits = installment.getCreditedPenalty() != null ? installment.getCreditedPenalty() : BigDecimal.ZERO; + final BigDecimal credits = principalCredits.add(feeCredits).add(penaltyCredits); + outstandingLoanPrincipalBalance = outstandingLoanPrincipalBalance.add(principalCredits); + + totalPrincipalDisbursed = totalPrincipalDisbursed.add(disbursedAmount); + + Integer daysInPeriod = 0; + if (fromDate != null) { + daysInPeriod = DateUtils.getExactDifferenceInDays(fromDate, dueDate); + loanTermInDays = loanTermInDays + daysInPeriod; + } + + final BigDecimal principalDue = installment.getPrincipal() != null ? installment.getPrincipal() : BigDecimal.ZERO; + totalPrincipalExpected = totalPrincipalExpected.plus(principalDue); + final BigDecimal principalPaid = installment.getPrincipalCompleted() != null ? installment.getPrincipalCompleted() + : BigDecimal.ZERO; + totalPrincipalPaid = totalPrincipalPaid.plus(principalPaid); + final BigDecimal principalWrittenOff = installment.getPrincipalWrittenOff() != null ? installment.getPrincipalWrittenOff() + : BigDecimal.ZERO; + + final BigDecimal principalOutstanding = principalDue.subtract(principalPaid).subtract(principalWrittenOff); + + final BigDecimal interestExpectedDue = installment.getInterestCharged() != null ? installment.getInterestCharged() + : BigDecimal.ZERO; + totalInterestCharged = totalInterestCharged.plus(interestExpectedDue); + final BigDecimal interestPaid = installment.getInterestPaid() != null ? installment.getInterestPaid() : BigDecimal.ZERO; + final BigDecimal interestWaived = installment.getInterestWaived() != null ? installment.getInterestWaived() : BigDecimal.ZERO; + final BigDecimal interestWrittenOff = installment.getInterestWrittenOff() != null ? installment.getInterestWrittenOff() + : BigDecimal.ZERO; + final BigDecimal accrualInterest = installment.getInterestAccrued() != null ? installment.getInterestAccrued() + : BigDecimal.ZERO; + + final BigDecimal interestActualDue = interestExpectedDue.subtract(interestWaived).subtract(interestWrittenOff); + final BigDecimal interestOutstanding = interestActualDue.subtract(interestPaid); + + final BigDecimal feeChargesExpectedDue = installment.getFeeChargesCharged() != null ? installment.getFeeChargesCharged() + : BigDecimal.ZERO; + totalFeeChargesCharged = totalFeeChargesCharged.plus(feeChargesExpectedDue); + final BigDecimal feeChargesPaid = installment.getFeeChargesPaid() != null ? installment.getFeeChargesPaid() : BigDecimal.ZERO; + final BigDecimal feeChargesWaived = installment.getFeeChargesWaived() != null ? installment.getFeeChargesWaived() + : BigDecimal.ZERO; + final BigDecimal feeChargesWrittenOff = installment.getFeeChargesWrittenOff() != null ? installment.getFeeChargesWrittenOff() + : BigDecimal.ZERO; + + final BigDecimal feeChargesActualDue = feeChargesExpectedDue.subtract(feeChargesWaived).subtract(feeChargesWrittenOff); + final BigDecimal feeChargesOutstanding = feeChargesActualDue.subtract(feeChargesPaid); + + final BigDecimal penaltyChargesExpectedDue = installment.getPenaltyCharges() != null ? installment.getPenaltyCharges() + : BigDecimal.ZERO; + totalPenaltyChargesCharged = totalPenaltyChargesCharged.plus(penaltyChargesExpectedDue); + final BigDecimal penaltyChargesPaid = installment.getPenaltyChargesPaid() != null ? installment.getPenaltyChargesPaid() + : BigDecimal.ZERO; + final BigDecimal penaltyChargesWaived = installment.getPenaltyChargesWaived() != null ? installment.getPenaltyChargesWaived() + : BigDecimal.ZERO; + final BigDecimal penaltyChargesWrittenOff = installment.getPenaltyChargesWrittenOff() != null + ? installment.getPenaltyChargesWrittenOff() + : BigDecimal.ZERO; + + final BigDecimal totalPaidInAdvanceForPeriod = installment.getTotalPaidInAdvance() != null ? installment.getTotalPaidInAdvance() + : BigDecimal.ZERO; + final BigDecimal totalPaidLateForPeriod = installment.getTotalPaidLate() != null ? installment.getTotalPaidLate() + : BigDecimal.ZERO; + + final BigDecimal penaltyChargesActualDue = penaltyChargesExpectedDue.subtract(penaltyChargesWaived) + .subtract(penaltyChargesWrittenOff); + final BigDecimal penaltyChargesOutstanding = penaltyChargesActualDue.subtract(penaltyChargesPaid); + + final BigDecimal totalExpectedCostOfLoanForPeriod = interestExpectedDue.add(feeChargesExpectedDue) + .add(penaltyChargesExpectedDue); + + final BigDecimal totalDueForPeriod = principalDue.add(totalExpectedCostOfLoanForPeriod); + final BigDecimal totalPaidForPeriod = principalPaid.add(interestPaid).add(feeChargesPaid).add(penaltyChargesPaid); + final BigDecimal totalWaivedForPeriod = interestWaived.add(feeChargesWaived).add(penaltyChargesWaived); + totalWaived = totalWaived.plus(totalWaivedForPeriod); + final BigDecimal totalWrittenOffForPeriod = principalWrittenOff.add(interestWrittenOff).add(feeChargesWrittenOff) + .add(penaltyChargesWrittenOff); + totalWrittenOff = totalWrittenOff.plus(totalWrittenOffForPeriod); + + final BigDecimal totalOutstandingForPeriod = principalOutstanding.add(interestOutstanding).add(feeChargesOutstanding) + .add(penaltyChargesOutstanding); + + totalRepaymentExpected = totalRepaymentExpected.plus(totalDueForPeriod); + totalRepayment = totalRepayment.plus(totalPaidForPeriod); + totalPaidInAdvance = totalPaidInAdvance.plus(totalPaidInAdvanceForPeriod); + totalPaidLate = totalPaidLate.plus(totalPaidLateForPeriod); + totalOutstanding = totalOutstanding.plus(totalOutstandingForPeriod); + totalCredits = totalCredits.add(credits); + + if (fromDate == null) { + fromDate = lastDueDate; + } + + BigDecimal outstandingPrincipalBalanceOfLoan = outstandingLoanPrincipalBalance.subtract(principalDue); + + // update based on current period values + lastDueDate = dueDate; + outstandingLoanPrincipalBalance = outstandingLoanPrincipalBalance.subtract(principalDue); + + final boolean isDownPayment = installment.isDownPayment(); + + LoanSchedulePeriodData periodData; + + periodData = LoanSchedulePeriodData.periodWithPayments(period, fromDate, dueDate, obligationsMetOnDate, complete, principalDue, + principalPaid, principalWrittenOff, principalOutstanding, outstandingPrincipalBalanceOfLoan, interestExpectedDue, + interestPaid, interestWaived, interestWrittenOff, interestOutstanding, feeChargesExpectedDue, feeChargesPaid, + feeChargesWaived, feeChargesWrittenOff, feeChargesOutstanding, penaltyChargesExpectedDue, penaltyChargesPaid, + penaltyChargesWaived, penaltyChargesWrittenOff, penaltyChargesOutstanding, totalPaidForPeriod, + totalPaidInAdvanceForPeriod, totalPaidLateForPeriod, totalWaivedForPeriod, totalWrittenOffForPeriod, credits, + isDownPayment, accrualInterest); + + periods.add(periodData); + } + + return new LoanScheduleData(currency, periods, loanTermInDays, totalPrincipalDisbursed, totalPrincipalExpected.getAmount(), + totalPrincipalPaid.getAmount(), totalInterestCharged.getAmount(), totalFeeChargesCharged.getAmount(), + totalPenaltyChargesCharged.getAmount(), totalWaived.getAmount(), totalWrittenOff.getAmount(), + totalRepaymentExpected.getAmount(), totalRepayment.getAmount(), totalPaidInAdvance.getAmount(), totalPaidLate.getAmount(), + totalOutstanding.getAmount(), totalCredits.getAmount()); + } + + private List collectEligibleDisbursementData(LoanScheduleType loanScheduleType, + Collection disbursementData, LocalDate fromDate, LocalDate dueDate, Set disbursementPeriodIds, + DisbursementData mainDisbursement, boolean excludePastUnDisbursed) { + List disbursementDataList = new ArrayList<>(); + + boolean hasMultipleTranchesOnSameDate = hasMultipleTranchesOnSameDate(disbursementData); + + if (hasMultipleTranchesOnSameDate) { + Map> disbursementsByDate = new HashMap<>(); + + for (final DisbursementData data : disbursementData) { + boolean isDueForDisbursement = data.isDueForDisbursement(loanScheduleType, fromDate, dueDate); + boolean isEligible = ((fromDate.equals(mainDisbursement.disbursementDate()) && data.disbursementDate().equals(fromDate)) + || (fromDate.equals(dueDate) && data.disbursementDate().equals(fromDate)) + || canAddDisbursementData(data, isDueForDisbursement, excludePastUnDisbursed)) + && !disbursementPeriodIds.contains(data.getId()); + + if (isEligible) { + disbursementsByDate.computeIfAbsent(data.disbursementDate(), k -> new ArrayList<>()).add(data); + disbursementPeriodIds.add(data.getId()); + } + } + + for (Map.Entry> entry : disbursementsByDate.entrySet()) { + List sameDateDisbursements = entry.getValue(); + + if (sameDateDisbursements.size() > 1) { + List disbursedTranches = sameDateDisbursements.stream().filter(DisbursementData::isDisbursed) + .collect(Collectors.toList()); + + if (!disbursedTranches.isEmpty()) { + for (DisbursementData data : disbursedTranches) { + disbursementDataList.add(new LoanSchedulePeriodDataWrapper(data, data.disbursementDate(), true)); + } + } else { + for (DisbursementData data : sameDateDisbursements) { + disbursementDataList.add(new LoanSchedulePeriodDataWrapper(data, data.disbursementDate(), true)); + } + } + } else { + DisbursementData data = sameDateDisbursements.get(0); + disbursementDataList.add(new LoanSchedulePeriodDataWrapper(data, data.disbursementDate(), true)); + } + } + } else { + for (final DisbursementData data : disbursementData) { + boolean isDueForDisbursement = data.isDueForDisbursement(loanScheduleType, fromDate, dueDate); + boolean isEligible = ((fromDate.equals(mainDisbursement.disbursementDate()) && data.disbursementDate().equals(fromDate)) + || (fromDate.equals(dueDate) && data.disbursementDate().equals(fromDate)) + || canAddDisbursementData(data, isDueForDisbursement, excludePastUnDisbursed)) + && !disbursementPeriodIds.contains(data.getId()); + + if (isEligible) { + disbursementDataList.add(new LoanSchedulePeriodDataWrapper(data, data.disbursementDate(), true)); + disbursementPeriodIds.add(data.getId()); + } + } + } + + return disbursementDataList; + } + + private boolean hasMultipleTranchesOnSameDate(Collection disbursementData) { + if (disbursementData == null || disbursementData.size() <= 1) { + return false; + } + return disbursementData.stream().collect(Collectors.groupingBy(DisbursementData::disbursementDate, Collectors.counting())).values() + .stream().anyMatch(count -> count > 1); + } + + private List collectEligibleCapitalizedIncomeData( + Collection capitalizedIncomeData, LocalDate fromDate, LocalDate dueDate, + Set disbursementPeriodIds) { + List capitalizedIncomeDataList = new ArrayList<>(); + // Collect eligible capitalized income data + for (LoanTransactionRepaymentPeriodData data : capitalizedIncomeData) { + boolean isEligible = canAddCapitalizedIncomeData(data, fromDate, dueDate) + && !disbursementPeriodIds.contains(data.getTransactionId()); + + if (isEligible) { + capitalizedIncomeDataList.add(new LoanSchedulePeriodDataWrapper(data, data.getDate(), false)); + disbursementPeriodIds.add(data.getTransactionId()); + } + } + return capitalizedIncomeDataList; + } + + private BigDecimal fillLoanSchedulePeriodData(List periods, + List combinedDataList, BigDecimal disbursementChargeAmount, BigDecimal waivedChargeAmount, + BigDecimal outstandingLoanPrincipalBalance) { + // Process all collected data in chronological order + for (LoanSchedulePeriodDataWrapper dataItem : combinedDataList) { + LoanSchedulePeriodData periodData; + if (dataItem.isDisbursement()) { + // Process disbursement data + DisbursementData data = (DisbursementData) dataItem.getData(); + periodData = createLoanSchedulePeriodData(data, disbursementChargeAmount, waivedChargeAmount); + } else { + // Process capitalized income data + LoanTransactionRepaymentPeriodData data = (LoanTransactionRepaymentPeriodData) dataItem.getData(); + periodData = createLoanSchedulePeriodData(data); + } + + // Common processing for both data types + periods.add(periodData); + outstandingLoanPrincipalBalance = outstandingLoanPrincipalBalance.add(periodData.getPrincipalDisbursed()); + } + return outstandingLoanPrincipalBalance; + } + + private BigDecimal calculateDisbursedAmount(List combinedDataList) { + BigDecimal disbursedAmount = BigDecimal.ZERO; + for (LoanSchedulePeriodDataWrapper dataItem : combinedDataList) { + if (dataItem.isDisbursement()) { + DisbursementData data = (DisbursementData) dataItem.getData(); + disbursedAmount = disbursedAmount.add(data.getPrincipal()); + } + } + return disbursedAmount; + } + + private int sortPeriodDataHolders(LoanSchedulePeriodDataWrapper item1, LoanSchedulePeriodDataWrapper item2) { + int dateComparison = item1.getDate().compareTo(item2.getDate()); + if (dateComparison == 0 && item1.isDisbursement() != item2.isDisbursement()) { + // If dates are equal, prioritize disbursement data + return item1.isDisbursement() ? -1 : 1; + } + return dateComparison; + } + + private LoanSchedulePeriodData createLoanSchedulePeriodData(final DisbursementData data, BigDecimal disbursementChargeAmount, + BigDecimal waivedChargeAmount) { + BigDecimal chargeAmount = data.getChargeAmount() == null ? disbursementChargeAmount + : disbursementChargeAmount.add(data.getChargeAmount()).subtract(waivedChargeAmount); + return LoanSchedulePeriodData.disbursementOnlyPeriod(data.disbursementDate(), data.getPrincipal(), chargeAmount, + data.isDisbursed()); + } + + private LoanSchedulePeriodData createLoanSchedulePeriodData(final LoanTransactionRepaymentPeriodData data) { + BigDecimal feeCharges = Objects.isNull(data.getFeeChargesPortion()) ? BigDecimal.ZERO : data.getFeeChargesPortion(); + return LoanSchedulePeriodData.disbursementOnlyPeriod(data.getDate(), data.getAmount(), feeCharges, !data.isReversed()); + } + + private boolean canAddDisbursementData(DisbursementData data, boolean isDueForDisbursement, boolean excludePastUnDisbursed) { + return (!excludePastUnDisbursed || data.isDisbursed() || !DateUtils.isBeforeBusinessDate(data.disbursementDate())) + && isDueForDisbursement; + } + + private boolean canAddCapitalizedIncomeData(LoanTransactionRepaymentPeriodData data, LocalDate fromDate, LocalDate dueDate) { + return !data.isReversed() && DateUtils.isDateInRangeFromInclusiveToExclusive(fromDate, dueDate, data.getDate()); + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reaging/LoanReAgingServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reaging/LoanReAgingService.java similarity index 76% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reaging/LoanReAgingServiceImpl.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reaging/LoanReAgingService.java index ba9703f4ec5..7ae81126fa7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reaging/LoanReAgingServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reaging/LoanReAgingService.java @@ -22,10 +22,12 @@ 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,14 +42,19 @@ import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.reaging.LoanReAgeTransactionBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.reaging.LoanUndoReAgeTransactionBusinessEvent; 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.common.domain.PeriodFrequencyType; import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants; import org.apache.fineract.portfolio.loanaccount.api.LoanReAgingApiConstants; +import org.apache.fineract.portfolio.loanaccount.data.DisbursementData; +import org.apache.fineract.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData; import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO; import org.apache.fineract.portfolio.loanaccount.domain.Loan; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory; 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.reaging.LoanReAgeInterestHandlingType; @@ -56,8 +63,12 @@ import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.MoneyHolder; import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.TransactionCtx; import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionNotFoundException; +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.LoanUtilService; import org.apache.fineract.portfolio.loanaccount.service.ReprocessLoanTransactionsService; @@ -69,7 +80,7 @@ @Service @RequiredArgsConstructor @Transactional -public class LoanReAgingServiceImpl { +public class LoanReAgingService { private final LoanAssembler loanAssembler; private final LoanReAgingValidator reAgingValidator; @@ -83,18 +94,15 @@ public class LoanReAgingServiceImpl { private final LoanScheduleService loanScheduleService; private final ReprocessLoanTransactionsService reprocessLoanTransactionsService; private final CodeValueRepository codeValueRepository; + private final LoanRepaymentScheduleService loanRepaymentScheduleService; + private final LoanReadPlatformService loanReadPlatformService; + private final LoanCapitalizedIncomeBalanceRepository loanCapitalizedIncomeBalanceRepository; - public CommandProcessingResult reAge(Long loanId, JsonCommand command) { - Loan loan = loanAssembler.assembleFrom(loanId); + public CommandProcessingResult reAge(final Long loanId, final JsonCommand command) { + final Loan loan = loanAssembler.assembleFrom(loanId); reAgingValidator.validateReAge(loan, command); - Map changes = new LinkedHashMap<>(); - changes.put(LoanReAgingApiConstants.localeParameterName, command.locale()); - changes.put(LoanReAgingApiConstants.dateFormatParameterName, command.dateFormat()); - - LoanTransaction reAgeTransaction = createReAgeTransaction(loan, command); - LoanReAgeParameter reAgeParameter = createReAgeParameter(reAgeTransaction, command); - reAgeTransaction.setLoanReAgeParameter(reAgeParameter); + final LoanTransaction reAgeTransaction = createReAgeTransaction(loan, command); loanTransactionRepository.saveAndFlush(reAgeTransaction); final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = loanRepaymentScheduleTransactionProcessorFactory .determineProcessor(loan.transactionProcessingStrategy()); @@ -116,7 +124,12 @@ public CommandProcessingResult reAge(Long loanId, JsonCommand command) { new TransactionCtx(loan.getCurrency(), loan.getRepaymentScheduleInstallments(), loan.getActiveCharges(), new MoneyHolder(loan.getTotalOverpaidAsMoney()), null)); } + loan.updateLoanScheduleDependentDerivedFields(); + + final Map changes = new LinkedHashMap<>(); + changes.put(LoanReAgingApiConstants.localeParameterName, command.locale()); + changes.put(LoanReAgingApiConstants.dateFormatParameterName, command.dateFormat()); persistNote(loan, command, changes); // delinquency recalculation will be triggered by the event in a decoupled way via a listener @@ -133,6 +146,39 @@ public CommandProcessingResult reAge(Long loanId, JsonCommand command) { .with(changes).build(); } + @Transactional(readOnly = true) + public LoanScheduleData previewReAge(final Long loanId, final JsonCommand command) { + final Loan loan = loanAssembler.assembleFrom(loanId); + reAgingValidator.validateReAge(loan, command); + + final LoanTransaction reAgeTransaction = createReAgeTransaction(loan, command); + + if (reAgeTransaction.getTransactionDate().isBefore(reAgeTransaction.getSubmittedOnDate())) { + reprocessLoanTransactionsService.reprocessTransactionsWithPostTransactionChecks(loan, reAgeTransaction.getTransactionDate()); + } + + final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = loanRepaymentScheduleTransactionProcessorFactory + .determineProcessor(loan.transactionProcessingStrategy()); + loanRepaymentScheduleTransactionProcessor.processLatestTransaction(reAgeTransaction, new TransactionCtx(loan.getCurrency(), + loan.getRepaymentScheduleInstallments(), loan.getActiveCharges(), new MoneyHolder(loan.getTotalOverpaidAsMoney()), null)); + + 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(loanId); + final Collection capitalizedIncomeData = loanCapitalizedIncomeBalanceRepository + .findRepaymentPeriodDataByLoanId(loanId); + 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()); + } + public CommandProcessingResult undoReAge(Long loanId, JsonCommand command) { Loan loan = loanAssembler.assembleFrom(loanId); reAgingValidator.validateUndoReAge(loan, command); @@ -199,8 +245,13 @@ private LoanTransaction createReAgeTransaction(Loan loan, JsonCommand command) { Money txPrincipal = loan.getTotalPrincipalOutstandingUntil(transactionDate); BigDecimal txPrincipalAmount = txPrincipal.getAmount(); - return new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.REAGE, transactionDate, txPrincipalAmount, txPrincipalAmount, - ZERO, ZERO, ZERO, null, false, null, txExternalId); + final LoanTransaction reAgeTransaction = new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.REAGE, transactionDate, + txPrincipalAmount, txPrincipalAmount, ZERO, ZERO, ZERO, null, false, null, txExternalId); + + final LoanReAgeParameter reAgeParameter = createReAgeParameter(reAgeTransaction, command); + reAgeTransaction.setLoanReAgeParameter(reAgeParameter); + + return reAgeTransaction; } private LoanReAgeParameter createReAgeParameter(LoanTransaction reAgeTransaction, JsonCommand command) { @@ -235,4 +286,5 @@ private void persistNote(Loan loan, JsonCommand command, Map cha this.noteRepository.saveAndFlush(newNote); } } + } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java index f7dfa1329d3..4bef7ee8e6a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java @@ -152,6 +152,7 @@ import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService; import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformServiceImpl; import org.apache.fineract.portfolio.loanaccount.service.LoanRefundService; +import org.apache.fineract.portfolio.loanaccount.service.LoanRepaymentScheduleService; import org.apache.fineract.portfolio.loanaccount.service.LoanScheduleService; import org.apache.fineract.portfolio.loanaccount.service.LoanStatusChangePlatformService; import org.apache.fineract.portfolio.loanaccount.service.LoanStatusChangePlatformServiceImpl; @@ -350,7 +351,8 @@ public LoanReadPlatformServiceImpl loanReadPlatformService(JdbcTemplate jdbcTemp LoanTransactionProcessingService loanTransactionProcessingService, LoanBalanceService loanBalanceService, LoanCapitalizedIncomeBalanceRepository loanCapitalizedIncomeBalanceRepository, LoanBuyDownFeeBalanceRepository loanBuyDownFeeBalanceRepository, - @Lazy InterestRefundServiceDelegate interestRefundServiceDelegate, LoanMaximumAmountCalculator loanMaximumAmountCalculator) { + @Lazy InterestRefundServiceDelegate interestRefundServiceDelegate, LoanMaximumAmountCalculator loanMaximumAmountCalculator, + LoanRepaymentScheduleService loanRepaymentScheduleService) { return new LoanReadPlatformServiceImpl(jdbcTemplate, context, loanRepositoryWrapper, applicationCurrencyRepository, loanProductReadPlatformService, clientReadPlatformService, groupReadPlatformService, loanDropdownReadPlatformService, fundReadPlatformService, chargeReadPlatformService, codeValueReadPlatformService, calendarReadPlatformService, @@ -359,7 +361,7 @@ public LoanReadPlatformServiceImpl loanReadPlatformService(JdbcTemplate jdbcTemp delinquencyReadPlatformService, loanTransactionRepository, loanChargePaidByReadService, loanTransactionRelationReadService, loanForeclosureValidator, loanTransactionMapper, loanTransactionProcessingService, loanBalanceService, loanCapitalizedIncomeBalanceRepository, loanBuyDownFeeBalanceRepository, interestRefundServiceDelegate, - loanMaximumAmountCalculator); + loanMaximumAmountCalculator, loanRepaymentScheduleService); } @Bean