diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanStepDef.java index 2ab4058a170..940abca2e8e 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanStepDef.java @@ -1352,6 +1352,21 @@ public void loanStatus(String statusExpected) throws IOException { .isEqualTo(loanStatusExpectedValue); } + @Then("Loan closedon_date is {}") + public void loanClosedonDate(String date) throws IOException { + Response loanCreateResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); + long loanId = loanCreateResponse.body().getLoanId(); + + Response loanDetailsResponse = loansApi.retrieveLoan(loanId, false, "", "", "").execute(); + ErrorHelper.checkSuccessfulApiCall(loanDetailsResponse); + testContext().set(TestContextKey.LOAN_RESPONSE, loanDetailsResponse); + if (date == null || "null".equals(date)) { + assertThat(loanDetailsResponse.body().getTimeline().getClosedOnDate()).isNull(); + } else { + assertThat(loanDetailsResponse.body().getTimeline().getClosedOnDate()).isEqualTo(date); + } + } + @Then("Admin can successfully set Fraud flag to the loan") public void setFraud() throws IOException { Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); 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 07e2df118f2..38e437e3abf 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/Loan.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/Loan.feature @@ -1244,6 +1244,20 @@ Feature: Loan | actualMaturityDate | expectedMaturityDate | | 01 July 2023 | 01 July 2023 | + Scenario: Verify that closed date is updated on repayment reversal + When Admin sets the business date to "01 June 2023" + When Admin creates a client with random data + When Admin creates a new default Loan with date: "01 June 2023" + And Admin successfully approves the loan on "01 June 2023" with "1000" amount and expected disbursement date on "01 June 2023" + When Admin successfully disburse the loan on "01 June 2023" with "1000" EUR transaction amount + Then Loan status will be "ACTIVE" + When Admin sets the business date to "20 June 2023" + And Customer makes "AUTOPAY" repayment on "20 June 2023" with 1000 EUR transaction amount + Then Loan status will be "CLOSED_OBLIGATIONS_MET" + When Admin sets the business date to "20 June 2023" + When Customer undo "1"th "Repayment" transaction made on "20 June 2023" + Then Loan status will be "ACTIVE" + Then Loan closedon_date is null Scenario: As an admin I would like to delete a loan using external id When Admin sets the business date to the actual date diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachine.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachine.java index 52b84de3572..6bc5d61bb13 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachine.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/DefaultLoanLifecycleStateMachine.java @@ -49,6 +49,17 @@ public void transition(final LoanEvent loanEvent, final Loan loan) { // in case of Loan creation, a LoanCreatedBusinessEvent is also raised, no need to send a status change businessEventNotifierService.notifyPostBusinessEvent(new LoanStatusChangedBusinessEvent(loan)); } + + // set mandatory field states based on new status after the transition + switch (newStatus) { + case ACTIVE -> { + if (loan.getClosedOnDate() != null) { + loan.setClosedOnDate(null); + } + } + default -> { + } + } } } @@ -132,6 +143,7 @@ private LoanStatus getNextStatus(LoanEvent loanEvent, Loan loan) { if (anyOfAllowedWhenComingFrom(from, LoanStatus.CLOSED_OBLIGATIONS_MET, LoanStatus.CLOSED_WRITTEN_OFF, LoanStatus.CLOSED_RESCHEDULE_OUTSTANDING_AMOUNT)) { newState = activeTransition(); + loan.setClosedOnDate(null); } break; case LOAN_INITIATE_TRANSFER: