From ee29ce23acadd99ca7f4bb2e59eac9426a11522e Mon Sep 17 00:00:00 2001 From: mariiaKraievska Date: Fri, 6 Jun 2025 14:59:31 +0300 Subject: [PATCH] FINERACT-2279: Contract Termination - Undo --- .../service/CommandWrapperBuilder.java | 9 +++ .../test/factory/LoanRequestFactory.java | 4 + .../messaging/event/EventCheckHelper.java | 5 ++ ...nUndoContractTerminationBusinessEvent.java | 27 +++++++ .../test/stepdef/loan/LoanStepDef.java | 29 +++++++ .../fineract/test/support/TestContextKey.java | 1 + .../features/LoanContractTermination.feature | 80 ++++++++++++++++++- ...nUndoContractTerminationBusinessEvent.java | 35 ++++++++ .../loanaccount/api/LoanApiConstants.java | 1 + .../data/LoanTransactionEnumData.java | 2 + .../portfolio/loanaccount/domain/Loan.java | 4 + .../LoanTransactionValidator.java | 2 + .../module/loan/module-changelog-master.xml | 1 + ...d_loan_undo_contract_termination_event.xml | 31 +++++++ .../ProgressiveLoanTransactionValidator.java | 2 + ...ogressiveLoanTransactionValidatorImpl.java | 51 ++++++++++++ .../loanaccount/api/LoansApiResource.java | 2 + .../api/LoansApiResourceSwagger.java | 2 + ...LoanContractTerminationCommandHandler.java | 40 ++++++++++ .../LoanTransactionValidatorImpl.java | 8 ++ .../LoanContractTerminationServiceImpl.java | 70 ++++++++++++++++ ...entConfigurationValidationServiceTest.java | 4 +- .../ExternalEventConfigurationHelper.java | 5 ++ 23 files changed, 412 insertions(+), 3 deletions(-) create mode 100644 fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/transaction/LoanUndoContractTerminationBusinessEvent.java create mode 100644 fineract-loan/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/transaction/LoanUndoContractTerminationBusinessEvent.java create mode 100644 fineract-loan/src/main/resources/db/changelog/tenant/module/loan/parts/1030_add_loan_undo_contract_termination_event.xml create mode 100644 fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/contracttermination/UndoLoanContractTerminationCommandHandler.java diff --git a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java index 48215fbe9..b470b77b5 100644 --- a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java +++ b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java @@ -3849,4 +3849,13 @@ public class CommandWrapperBuilder { this.href = "/loans/" + loanId; return this; } + + public CommandWrapperBuilder undoContractTermination(final Long loanId) { + this.actionName = "CONTRACT_TERMINATION_UNDO"; + this.entityName = "LOAN"; + this.entityId = loanId; + this.loanId = loanId; + this.href = "/loans/" + loanId; + return this; + } } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanRequestFactory.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanRequestFactory.java index c48f83599..4c7b0fc28 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanRequestFactory.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanRequestFactory.java @@ -305,6 +305,10 @@ public class LoanRequestFactory { .locale(DEFAULT_LOCALE).note("Capitalized Income"); } + public static PostLoansLoanIdRequest defaultContractTerminationUndoRequest() { + return new PostLoansLoanIdRequest().note("Contract Termination Undo"); + } + public static PostLoansLoanIdRequest defaultLoanContractTerminationRequest() { return new PostLoansLoanIdRequest().dateFormat(DATE_FORMAT).locale(DEFAULT_LOCALE).note("Contract Termination"); } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java index cec77bc30..f7e0ea509 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java @@ -79,6 +79,7 @@ import org.apache.fineract.test.messaging.event.loan.transaction.LoanTransaction import org.apache.fineract.test.messaging.event.loan.transaction.LoanTransactionMakeRepaymentPostEvent; import org.apache.fineract.test.messaging.event.loan.transaction.LoanTransactionMerchantIssuedRefundPostEvent; import org.apache.fineract.test.messaging.event.loan.transaction.LoanTransactionPayoutRefundPostEvent; +import org.apache.fineract.test.messaging.event.loan.transaction.LoanUndoContractTerminationBusinessEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import retrofit2.Response; @@ -273,6 +274,10 @@ public class EventCheckHelper { eventAssertionBuilder.extractingData(LoanTransactionAdjustmentDataV1::getNewTransactionDetail).isEqualTo(null); } + public void loanUndoContractTerminationEventCheck(final GetLoansLoanIdTransactions transaction) { + eventAssertion.assertEventRaised(LoanUndoContractTerminationBusinessEvent.class, transaction.getId()); + } + private boolean areBigDecimalValuesEqual(BigDecimal actual, BigDecimal expected) { log.debug("--- Checking BigDecimal values.... ---"); log.debug("Actual: {}", actual); diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/transaction/LoanUndoContractTerminationBusinessEvent.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/transaction/LoanUndoContractTerminationBusinessEvent.java new file mode 100644 index 000000000..bf3582442 --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/transaction/LoanUndoContractTerminationBusinessEvent.java @@ -0,0 +1,27 @@ +/** + * 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.test.messaging.event.loan.transaction; + +public class LoanUndoContractTerminationBusinessEvent extends AbstractLoanTransactionEvent { + + @Override + public String getEventName() { + return "LoanUndoContractTerminationBusinessEvent"; + } +} 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 a42db60b9..a95218d8d 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 @@ -4471,6 +4471,35 @@ public class LoanStepDef extends AbstractStepDef { .isEqualTo(transactionId); } + @And("Admin successfully undoes loan contract termination") + public void undoLoanContractTermination() throws IOException { + final Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); + assert loanResponse.body() != null; + final Response loanContractTerminationResponse = testContext() + .get(TestContextKey.LOAN_CONTRACT_TERMINATION_RESPONSE); + assert loanContractTerminationResponse.body() != null; + final Long loanId = loanResponse.body().getLoanId(); + + final List transactions = Objects + .requireNonNull(loansApi.retrieveLoan(loanId, false, "transactions", "", "").execute().body()).getTransactions(); + + assert transactions != null; + final GetLoansLoanIdTransactions targetTransaction = transactions.stream().filter(t -> { + assert t.getType() != null; + return Boolean.TRUE.equals(t.getType().getContractTermination()); + }).findFirst().orElse(null); + + final PostLoansLoanIdRequest request = LoanRequestFactory.defaultContractTerminationUndoRequest(); + + final Response response = loansApi.stateTransitions(loanId, request, "undoContractTermination").execute(); + testContext().set(TestContextKey.LOAN_UNDO_CONTRACT_TERMINATION_RESPONSE, response); + ErrorHelper.checkSuccessfulApiCall(response); + assert targetTransaction != null; + eventCheckHelper.checkTransactionWithLoanTransactionAdjustmentBizEvent(targetTransaction); + eventCheckHelper.loanUndoContractTerminationEventCheck(targetTransaction); + eventCheckHelper.loanBalanceChangedEventCheck(loanId); + } + @Then("LoanTransactionContractTerminationPostBusinessEvent is raised on {string}") public void checkLoanTransactionContractTerminationPostBusinessEvent(final String date) throws IOException { final Response loanCreateResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); 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 59279800d..ddc015b5c 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 @@ -228,4 +228,5 @@ public abstract class TestContextKey { public static final String LOAN_CAPITALIZED_INCOME_ADJUSTMENT_RESPONSE = "loanCapitalizedIncomeAdjustmentResponse"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_CONTRACT_TERMINATION = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyInterestRecalculationContractTermination"; public static final String LOAN_CONTRACT_TERMINATION_RESPONSE = "loanContractTerminationResponse"; + public static final String LOAN_UNDO_CONTRACT_TERMINATION_RESPONSE = "loanUndoContractTerminationResponse"; } diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanContractTermination.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanContractTermination.feature index 531db393e..b49f061eb 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanContractTermination.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanContractTermination.feature @@ -1047,4 +1047,82 @@ Feature: Contract Termination | 31 March 2024 | Accrual | 1.72 | 0.0 | 1.72 | 0.0 | 0.0 | 0.0 | false | false | | 31 March 2024 | Accrual Adjustment | 0.57 | 0.0 | 0.57 | 0.0 | 0.0 | 0.0 | false | false | | 31 March 2024 | Contract Termination | 31.15 | 31.07 | 0.08 | 0.0 | 0.0 | 0.0 | false | true | - And Global configuration "is-principal-compounding-disabled-for-overdue-loans" is disabled \ No newline at end of file + And Global configuration "is-principal-compounding-disabled-for-overdue-loans" is disabled + + @TestRailId:C3738 + Scenario: Verify contract termination undo when interest recalculation is enabled - case when contract termination occurs on due date + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When Admin creates a fully customized loan with the following data: + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_CONTRACT_TERMINATION | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + Then Loan Repayment schedule has 6 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + Then Loan Repayment schedule has 6 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 17.01 | 0.0 | 0.0 | 85.04 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + When Admin sets the business date to "1 March 2024" + And Admin successfully terminates loan contract + Then Loan Repayment schedule 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 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 0.0 | 83.57 | 0.49 | 0.0 | 0.0 | 84.06 | 0.0 | 0.0 | 0.0 | 84.06 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.07 | 0.0 | 0.0 | 101.07 | 17.01 | 0.0 | 0.0 | 84.06 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 01 March 2024 | Accrual | 1.07 | 0.0 | 1.07 | 0.0 | 0.0 | 0.0 | false | false | + | 01 March 2024 | Contract Termination | 84.06 | 83.57 | 0.49 | 0.0 | 0.0 | 0.0 | false | false | + When Admin successfully undoes loan contract termination + Then Loan Repayment schedule has 6 periods, with the following data for periods: + | Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 17.01 | 0.0 | 0.0 | 85.04 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 01 March 2024 | Accrual | 1.07 | 0.0 | 1.07 | 0.0 | 0.0 | 0.0 | false | false | + | 01 March 2024 | Contract Termination | 84.06 | 83.57 | 0.49 | 0.0 | 0.0 | 0.0 | true | false | \ No newline at end of file diff --git a/fineract-loan/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/transaction/LoanUndoContractTerminationBusinessEvent.java b/fineract-loan/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/transaction/LoanUndoContractTerminationBusinessEvent.java new file mode 100644 index 000000000..1fddf8cab --- /dev/null +++ b/fineract-loan/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/transaction/LoanUndoContractTerminationBusinessEvent.java @@ -0,0 +1,35 @@ +/** + * 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.infrastructure.event.business.domain.loan.transaction; + +import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; + +public class LoanUndoContractTerminationBusinessEvent extends LoanTransactionBusinessEvent { + + private static final String TYPE = "LoanUndoContractTerminationBusinessEvent"; + + public LoanUndoContractTerminationBusinessEvent(LoanTransaction value) { + super(value); + } + + @Override + public String getType() { + return TYPE; + } +} diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java index d50a637dc..fea5061f3 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java @@ -180,6 +180,7 @@ public interface LoanApiConstants { String CAPITALIZED_INCOME_TRANSACTION_COMMAND = "capitalizedIncome"; String CAPITALIZED_INCOME_ADJUSTMENT_TRANSACTION_COMMAND = "capitalizedIncomeAdjustment"; String CONTRACT_TERMINATION_COMMAND = "contractTermination"; + String UNDO_CONTRACT_TERMINATION_COMMAND = "undoContractTermination"; // Data Validator names String LOAN_FRAUD_DATAVALIDATOR_PREFIX = "loans.fraud"; diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionEnumData.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionEnumData.java index a52d868ef..8785c1caa 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionEnumData.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionEnumData.java @@ -71,6 +71,7 @@ public class LoanTransactionEnumData implements Serializable { private final boolean capitalizedIncomeAmortization; private final boolean capitalizedIncomeAdjustment; private final boolean capitalizedIncomeAmortizationAdjustment; + private final boolean contractTermination; public LoanTransactionEnumData(final Long id, final String code, final String value) { this.id = id; @@ -112,6 +113,7 @@ public class LoanTransactionEnumData implements Serializable { this.capitalizedIncomeAdjustment = Long.valueOf(LoanTransactionType.CAPITALIZED_INCOME_ADJUSTMENT.getValue()).equals(this.id); this.capitalizedIncomeAmortizationAdjustment = Long .valueOf(LoanTransactionType.CAPITALIZED_INCOME_AMORTIZATION_ADJUSTMENT.getValue()).equals(this.id); + this.contractTermination = Long.valueOf(LoanTransactionType.CONTRACT_TERMINATION.getValue()).equals(this.id); } public boolean isRepaymentType() { diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java index f2ad4f94e..3c8d29df2 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java @@ -1789,6 +1789,10 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { return getLoanTransaction(e -> e.isNotReversed() && e.isChargeOff()); } + public LoanTransaction findContractTerminationTransaction() { + return getLoanTransaction(e -> e.isNotReversed() && e.isContractTermination()); + } + public void handleMaturityDateActivate() { if (this.expectedMaturityDate != null && !this.expectedMaturityDate.equals(this.actualMaturityDate)) { this.actualMaturityDate = this.expectedMaturityDate; diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanTransactionValidator.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanTransactionValidator.java index 5aa8ac7ce..1e77207de 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanTransactionValidator.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanTransactionValidator.java @@ -92,4 +92,6 @@ public interface LoanTransactionValidator { void validateNote(DataValidatorBuilder baseDataValidator, JsonElement element); void validateExternalId(DataValidatorBuilder baseDataValidator, JsonElement element); + + void validateReversalExternalId(DataValidatorBuilder baseDataValidator, JsonElement element); } diff --git a/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml index 50364a23a..16f44a802 100644 --- a/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml +++ b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/module-changelog-master.xml @@ -52,4 +52,5 @@ + diff --git a/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/parts/1030_add_loan_undo_contract_termination_event.xml b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/parts/1030_add_loan_undo_contract_termination_event.xml new file mode 100644 index 000000000..8f0bdad68 --- /dev/null +++ b/fineract-loan/src/main/resources/db/changelog/tenant/module/loan/parts/1030_add_loan_undo_contract_termination_event.xml @@ -0,0 +1,31 @@ + + + + + + + + + + diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanTransactionValidator.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanTransactionValidator.java index 0f0d2faa0..071859a01 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanTransactionValidator.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanTransactionValidator.java @@ -26,4 +26,6 @@ public interface ProgressiveLoanTransactionValidator extends LoanTransactionVali void validateCapitalizedIncome(JsonCommand command, Long loanId); void validateCapitalizedIncomeAdjustment(JsonCommand command, Long loanId, Long capitalizedIncomeTransactionId); + + void validateContractTerminationUndo(JsonCommand command, Long loanId); } diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanTransactionValidatorImpl.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanTransactionValidatorImpl.java index 54754195f..9abf35df4 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanTransactionValidatorImpl.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanTransactionValidatorImpl.java @@ -34,6 +34,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; +import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException; import org.apache.fineract.infrastructure.core.exception.InvalidJsonException; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.core.service.DateUtils; @@ -219,6 +220,47 @@ public class ProgressiveLoanTransactionValidatorImpl implements ProgressiveLoanT }); } + @Override + public void validateContractTerminationUndo(final JsonCommand command, final Long loanId) { + final String json = command.json(); + if (StringUtils.isBlank(json)) { + throw new InvalidJsonException(); + } + + final JsonElement element = this.fromApiJsonHelper.parse(json); + final Type typeOfMap = new TypeToken>() {}.getType(); + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, getContractTerminationUndoParameters()); + + Validator.validateOrThrow("loan.contract.termination.undo", baseDataValidator -> { + final Loan loan = this.loanRepositoryWrapper.findOneWithNotFoundDetection(loanId, true); + validateLoanClientIsActive(loan); + validateLoanGroupIsActive(loan); + + if (!loan.isOpen()) { + throw new GeneralPlatformDomainRuleException("error.msg.loan.is.not.active", + "Loan: " + loanId + " Undo Contract Termination is not allowed. Loan Account is not Active", loanId); + } + if (!loan.isContractTermination()) { + throw new GeneralPlatformDomainRuleException("error.msg.loan.is.not.contract.terminated", + "Loan: " + loanId + " is not contract terminated", loanId); + } + final LoanTransaction contractTerminationTransaction = loan.findContractTerminationTransaction(); + if (contractTerminationTransaction == null) { + throw new GeneralPlatformDomainRuleException("error.msg.loan.contract.termination.transaction.not.found", + "Loan: " + loanId + " contract termination transaction was not found", loanId); + } + if (!contractTerminationTransaction.equals(loan.getLastUserTransaction())) { + throw new GeneralPlatformDomainRuleException("error.msg.loan.contract.termination.is.not.the.last.user.transaction", + "Loan: " + loanId + + " contract termination cannot be undone. User transaction was found after contract termination!", + loanId); + } + + validateNote(baseDataValidator, element); + validateReversalExternalId(baseDataValidator, element); + }); + } + // Delegates @Override public void validateDisbursement(JsonCommand command, boolean isAccountTransfer, Long loanId) { @@ -368,6 +410,11 @@ public class ProgressiveLoanTransactionValidatorImpl implements ProgressiveLoanT loanTransactionValidator.validateExternalId(baseDataValidator, element); } + @Override + public void validateReversalExternalId(final DataValidatorBuilder baseDataValidator, final JsonElement element) { + loanTransactionValidator.validateReversalExternalId(baseDataValidator, element); + } + private Set getCapitalizedIncomeParameters() { return new HashSet<>( Arrays.asList("transactionDate", "dateFormat", "locale", "transactionAmount", "paymentTypeId", "note", "externalId")); @@ -377,4 +424,8 @@ public class ProgressiveLoanTransactionValidatorImpl implements ProgressiveLoanT return new HashSet<>( Arrays.asList("transactionDate", "dateFormat", "locale", "transactionAmount", "paymentTypeId", "note", "externalId")); } + + private Set getContractTerminationUndoParameters() { + return new HashSet<>(Arrays.asList("note", "reversalExternalId")); + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java index 04fcf11ce..058c7f914 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java @@ -1234,6 +1234,8 @@ public class LoansApiResource { commandRequest = builder.assignDelinquency(resolvedLoanId).build(); } else if (CommandParameterUtil.is(commandParam, LoanApiConstants.CONTRACT_TERMINATION_COMMAND)) { commandRequest = builder.applyContractTermination(resolvedLoanId).build(); + } else if (CommandParameterUtil.is(commandParam, LoanApiConstants.UNDO_CONTRACT_TERMINATION_COMMAND)) { + commandRequest = builder.undoContractTermination(resolvedLoanId).build(); } if (commandRequest == null) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java index d53dcaf6f..ce9379f75 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java @@ -733,6 +733,8 @@ final class LoansApiResourceSwagger { public boolean capitalizedIncomeAmortization; @Schema(example = "false") public boolean capitalizedIncomeAdjustment; + @Schema(example = "false") + public boolean contractTermination; } static final class GetLoansLoanIdPaymentDetailData { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/contracttermination/UndoLoanContractTerminationCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/contracttermination/UndoLoanContractTerminationCommandHandler.java new file mode 100644 index 000000000..ee244598f --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/handler/loan/contracttermination/UndoLoanContractTerminationCommandHandler.java @@ -0,0 +1,40 @@ +/** + * 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.handler.loan.contracttermination; + +import lombok.RequiredArgsConstructor; +import org.apache.fineract.commands.annotation.CommandType; +import org.apache.fineract.commands.handler.NewCommandSourceHandler; +import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.portfolio.loanaccount.service.contracttermination.LoanContractTerminationServiceImpl; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +@CommandType(entity = "LOAN", action = "CONTRACT_TERMINATION_UNDO") +public class UndoLoanContractTerminationCommandHandler implements NewCommandSourceHandler { + + private final LoanContractTerminationServiceImpl loanContractTerminationService; + + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + return loanContractTerminationService.undoContractTermination(command); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanTransactionValidatorImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanTransactionValidatorImpl.java index e91852a6a..4f635b98d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanTransactionValidatorImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanTransactionValidatorImpl.java @@ -1081,4 +1081,12 @@ public final class LoanTransactionValidatorImpl implements LoanTransactionValida baseDataValidator.reset().parameter("externalId").value(externalId).notExceedingLengthOf(100); } } + + @Override + public void validateReversalExternalId(final DataValidatorBuilder baseDataValidator, final JsonElement element) { + final String reversalExternalId = this.fromApiJsonHelper.extractStringNamed("reversalExternalId", element); + if (StringUtils.isNotBlank(reversalExternalId)) { + baseDataValidator.reset().parameter("reversalExternalId").value(reversalExternalId).notExceedingLengthOf(100); + } + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/contracttermination/LoanContractTerminationServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/contracttermination/LoanContractTerminationServiceImpl.java index 917dd21b2..28ee5ba50 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/contracttermination/LoanContractTerminationServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/contracttermination/LoanContractTerminationServiceImpl.java @@ -32,19 +32,25 @@ import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.ExternalIdFactory; +import org.apache.fineract.infrastructure.event.business.domain.loan.LoanAdjustTransactionBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.LoanBalanceChangedBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanTransactionContractTerminationPostBusinessEvent; +import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanUndoContractTerminationBusinessEvent; import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants; +import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository; import org.apache.fineract.portfolio.loanaccount.domain.LoanSubStatus; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType; +import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator; import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler; +import org.apache.fineract.portfolio.loanaccount.service.LoanScheduleService; import org.apache.fineract.portfolio.loanaccount.service.LoanTransactionService; import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService; +import org.apache.fineract.portfolio.loanaccount.service.ProgressiveLoanTransactionValidator; import org.apache.fineract.portfolio.loanaccount.service.ReprocessLoanTransactionsService; import org.apache.fineract.portfolio.note.domain.Note; import org.apache.fineract.portfolio.note.domain.NoteRepository; @@ -65,6 +71,9 @@ public class LoanContractTerminationServiceImpl { private final ExternalIdFactory externalIdFactory; private final BusinessEventNotifierService businessEventNotifierService; private final LoanTransactionService loanTransactionService; + private final LoanScheduleService loanScheduleService; + private final LoanChargeValidator loanChargeValidator; + private final ProgressiveLoanTransactionValidator loanTransactionValidator; public CommandProcessingResult applyContractTermination(final JsonCommand command) { final Loan loan = loanAssembler.assembleFrom(command.getLoanId()); @@ -116,6 +125,67 @@ public class LoanContractTerminationServiceImpl { .with(changes).build(); } + public CommandProcessingResult undoContractTermination(final JsonCommand command) { + final Long loanId = command.getLoanId(); + + loanTransactionValidator.validateContractTerminationUndo(command, loanId); + + final Loan loan = loanAssembler.assembleFrom(loanId); + final LoanTransaction contractTerminationTransaction = loan.findContractTerminationTransaction(); + + businessEventNotifierService.notifyPreBusinessEvent(new LoanUndoContractTerminationBusinessEvent(contractTerminationTransaction)); + businessEventNotifierService.notifyPreBusinessEvent( + new LoanAdjustTransactionBusinessEvent(new LoanAdjustTransactionBusinessEvent.Data(contractTerminationTransaction))); + + // check if reversalExternalId is provided + final String reversalExternalId = command.stringValueOfParameterNamedAllowingNull(LoanApiConstants.REVERSAL_EXTERNAL_ID_PARAMNAME); + final ExternalId reversalTxnExternalId = ExternalIdFactory.produce(reversalExternalId); + final Map changes = new LinkedHashMap<>(); + + // Add note if provided + final String noteText = command.stringValueOfParameterNamed("note"); + if (StringUtils.isNotBlank(noteText)) { + changes.put("note", noteText); + final Note note = Note.loanTransactionNote(loan, contractTerminationTransaction, noteText); + noteRepository.save(note); + } + + loanChargeValidator.validateRepaymentTypeTransactionNotBeforeAChargeRefund(contractTerminationTransaction.getLoan(), + contractTerminationTransaction, "reversed"); + contractTerminationTransaction.reverse(reversalTxnExternalId); + contractTerminationTransaction.manuallyAdjustedOrReversed(); + + loan.liftContractTerminationSubStatus(); + changes.put(LoanApiConstants.subStatusAttributeName, loan.getLoanSubStatus()); + loanTransactionRepository.saveAndFlush(contractTerminationTransaction); + + final ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, null, null); + if (loan.isCumulativeSchedule() && loan.isInterestBearingAndInterestRecalculationEnabled()) { + loanScheduleService.regenerateRepaymentScheduleWithInterestRecalculation(loan, scheduleGeneratorDTO); + } else if (loan.isProgressiveSchedule()) { + loanScheduleService.regenerateRepaymentSchedule(loan, scheduleGeneratorDTO); + } + + reprocessLoanTransactionsService.reprocessTransactions(loan); + + businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan)); + businessEventNotifierService.notifyPostBusinessEvent(new LoanUndoContractTerminationBusinessEvent(contractTerminationTransaction)); + + final LoanAdjustTransactionBusinessEvent.Data eventData = new LoanAdjustTransactionBusinessEvent.Data( + contractTerminationTransaction); + businessEventNotifierService.notifyPostBusinessEvent(new LoanAdjustTransactionBusinessEvent(eventData)); + + return new CommandProcessingResultBuilder() // + .withOfficeId(loan.getOfficeId()) // + .withClientId(loan.getClientId()) // + .withGroupId(loan.getGroupId()) // + .withLoanId(loanId) // + .withEntityId(contractTerminationTransaction.getId()) // + .withEntityExternalId(contractTerminationTransaction.getExternalId()) // + .with(changes) // + .build(); + } + public void validateContractTermination(final Loan loan) { final List dataValidationErrors = new ArrayList<>(); diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java index 6e56c097f..4e3df0710 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java @@ -109,7 +109,7 @@ public class ExternalEventConfigurationValidationServiceTest { "LoanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent", "LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent", "LoanTransactionContractTerminationPostBusinessEvent", "LoanCapitalizedIncomeAmortizationAdjustmentTransactionCreatedBusinessEvent", - "LoanCapitalizedIncomeTransactionCreatedBusinessEvent"); + "LoanCapitalizedIncomeTransactionCreatedBusinessEvent", "LoanUndoContractTerminationBusinessEvent"); List tenants = Arrays .asList(new FineractPlatformTenant(1L, "default", "Default Tenant", "Europe/Budapest", null)); @@ -199,7 +199,7 @@ public class ExternalEventConfigurationValidationServiceTest { "LoanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent", "LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent", "LoanTransactionContractTerminationPostBusinessEvent", "LoanCapitalizedIncomeAmortizationAdjustmentTransactionCreatedBusinessEvent", - "LoanCapitalizedIncomeTransactionCreatedBusinessEvent"); + "LoanCapitalizedIncomeTransactionCreatedBusinessEvent", "LoanUndoContractTerminationBusinessEvent"); List tenants = Arrays .asList(new FineractPlatformTenant(1L, "default", "Default Tenant", "Europe/Budapest", null)); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalEventConfigurationHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalEventConfigurationHelper.java index 5a993bbf7..4015dfb59 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalEventConfigurationHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalEventConfigurationHelper.java @@ -621,6 +621,11 @@ public class ExternalEventConfigurationHelper { loanCapitalizedIncomeTransactionCreatedBusinessEvent.put("enabled", false); defaults.add(loanCapitalizedIncomeTransactionCreatedBusinessEvent); + Map loanTransactionUndoContractTerminationBusinessEvent = new HashMap<>(); + loanTransactionUndoContractTerminationBusinessEvent.put("type", "LoanUndoContractTerminationBusinessEvent"); + loanTransactionUndoContractTerminationBusinessEvent.put("enabled", false); + defaults.add(loanTransactionUndoContractTerminationBusinessEvent); + return defaults; }