FINERACT-2232: Capitalized income - Business events
This commit is contained in:
+35
@@ -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 LoanCapitalizedIncomeTransactionCreatedBusinessEvent extends LoanTransactionBusinessEvent {
|
||||||
|
|
||||||
|
private static final String TYPE = "LoanCapitalizedIncomeTransactionCreatedBusinessEvent";
|
||||||
|
|
||||||
|
public LoanCapitalizedIncomeTransactionCreatedBusinessEvent(LoanTransaction value) {
|
||||||
|
super(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
@@ -34,6 +34,10 @@ import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
|||||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||||
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanBalanceChangedBusinessEvent;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanCapitalizedIncomeTransactionCreatedBusinessEvent;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeBalance;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeBalance;
|
||||||
@@ -61,6 +65,7 @@ public class CapitalizedIncomeWritePlatformServiceImpl implements CapitalizedInc
|
|||||||
private final LoanCapitalizedIncomeBalanceRepository capitalizedIncomeBalanceRepository;
|
private final LoanCapitalizedIncomeBalanceRepository capitalizedIncomeBalanceRepository;
|
||||||
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
||||||
private final LoanBalanceService loanBalanceService;
|
private final LoanBalanceService loanBalanceService;
|
||||||
|
private final BusinessEventNotifierService businessEventNotifierService;
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
@@ -101,6 +106,9 @@ public class CapitalizedIncomeWritePlatformServiceImpl implements CapitalizedInc
|
|||||||
// Post journal entries
|
// Post journal entries
|
||||||
journalEntryPoster.postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
journalEntryPoster.postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||||
|
|
||||||
|
businessEventNotifierService
|
||||||
|
.notifyPostBusinessEvent(new LoanCapitalizedIncomeTransactionCreatedBusinessEvent(capitalizedIncomeTransaction));
|
||||||
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan));
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withEntityId(capitalizedIncomeTransaction.getId()) //
|
.withEntityId(capitalizedIncomeTransaction.getId()) //
|
||||||
.withEntityExternalId(capitalizedIncomeTransaction.getExternalId()) //
|
.withEntityExternalId(capitalizedIncomeTransaction.getExternalId()) //
|
||||||
@@ -153,6 +161,10 @@ public class CapitalizedIncomeWritePlatformServiceImpl implements CapitalizedInc
|
|||||||
MathUtil.negativeToZero(capitalizedIncomeBalance.getUnrecognizedAmount().subtract(transactionAmount)));
|
MathUtil.negativeToZero(capitalizedIncomeBalance.getUnrecognizedAmount().subtract(transactionAmount)));
|
||||||
capitalizedIncomeBalanceRepository.save(capitalizedIncomeBalance);
|
capitalizedIncomeBalanceRepository.save(capitalizedIncomeBalance);
|
||||||
|
|
||||||
|
businessEventNotifierService.notifyPostBusinessEvent(
|
||||||
|
new LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent(savedCapitalizedIncomeAdjustment));
|
||||||
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan));
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withEntityId(savedCapitalizedIncomeAdjustment.getId()) //
|
.withEntityId(savedCapitalizedIncomeAdjustment.getId()) //
|
||||||
.withEntityExternalId(savedCapitalizedIncomeAdjustment.getExternalId()) //
|
.withEntityExternalId(savedCapitalizedIncomeAdjustment.getExternalId()) //
|
||||||
|
|||||||
+4
-2
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.loanaccount.starter;
|
|||||||
|
|
||||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||||
|
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||||
import org.apache.fineract.portfolio.loanaccount.repository.LoanCapitalizedIncomeBalanceRepository;
|
import org.apache.fineract.portfolio.loanaccount.repository.LoanCapitalizedIncomeBalanceRepository;
|
||||||
@@ -50,10 +51,11 @@ public class ProgressiveLoanAccountConfiguration {
|
|||||||
PaymentDetailWritePlatformService paymentDetailWritePlatformService, LoanJournalEntryPoster journalEntryPoster,
|
PaymentDetailWritePlatformService paymentDetailWritePlatformService, LoanJournalEntryPoster journalEntryPoster,
|
||||||
NoteWritePlatformService noteWritePlatformService, ExternalIdFactory externalIdFactory,
|
NoteWritePlatformService noteWritePlatformService, ExternalIdFactory externalIdFactory,
|
||||||
LoanCapitalizedIncomeBalanceRepository capitalizedIncomeBalanceRepository,
|
LoanCapitalizedIncomeBalanceRepository capitalizedIncomeBalanceRepository,
|
||||||
ReprocessLoanTransactionsService reprocessLoanTransactionsService, LoanBalanceService loanBalanceService) {
|
ReprocessLoanTransactionsService reprocessLoanTransactionsService, LoanBalanceService loanBalanceService,
|
||||||
|
BusinessEventNotifierService businessEventNotifierService) {
|
||||||
return new CapitalizedIncomeWritePlatformServiceImpl(loanTransactionValidator, loanAssembler, loanTransactionRepository,
|
return new CapitalizedIncomeWritePlatformServiceImpl(loanTransactionValidator, loanAssembler, loanTransactionRepository,
|
||||||
paymentDetailWritePlatformService, journalEntryPoster, noteWritePlatformService, externalIdFactory,
|
paymentDetailWritePlatformService, journalEntryPoster, noteWritePlatformService, externalIdFactory,
|
||||||
capitalizedIncomeBalanceRepository, reprocessLoanTransactionsService, loanBalanceService);
|
capitalizedIncomeBalanceRepository, reprocessLoanTransactionsService, loanBalanceService, businessEventNotifierService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|||||||
@@ -201,4 +201,5 @@
|
|||||||
<include file="parts/0180_add_version_field_to_loan_transaction.xml" relativeToChangelogFile="true" />
|
<include file="parts/0180_add_version_field_to_loan_transaction.xml" relativeToChangelogFile="true" />
|
||||||
<include file="parts/0181_add_capitalized_income_amortization_adjustment_transaction.xml" relativeToChangelogFile="true" />
|
<include file="parts/0181_add_capitalized_income_amortization_adjustment_transaction.xml" relativeToChangelogFile="true" />
|
||||||
<include file="parts/0182_transaction_summary_with_asset_owner_report_fix_charge_reason_and_add_buyback_intermediate.xml" relativeToChangelogFile="true" />
|
<include file="parts/0182_transaction_summary_with_asset_owner_report_fix_charge_reason_and_add_buyback_intermediate.xml" relativeToChangelogFile="true" />
|
||||||
|
<include file="parts/0183_add_LoanCapitalizedIncomeTransactionCreatedBusinessEvent.xml" relativeToChangelogFile="true" />
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
|
|||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||||
|
<changeSet id="1" author="fineract">
|
||||||
|
<insert tableName="m_external_event_configuration">
|
||||||
|
<column name="type" value="LoanCapitalizedIncomeTransactionCreatedBusinessEvent"/>
|
||||||
|
<column name="enabled" valueBoolean="false"/>
|
||||||
|
</insert>
|
||||||
|
</changeSet>
|
||||||
|
</databaseChangeLog>
|
||||||
+4
-2
@@ -108,7 +108,8 @@ public class ExternalEventConfigurationValidationServiceTest {
|
|||||||
"LoanTransactionInterestRefundPreBusinessEvent", "LoanAccrualAdjustmentTransactionBusinessEvent",
|
"LoanTransactionInterestRefundPreBusinessEvent", "LoanAccrualAdjustmentTransactionBusinessEvent",
|
||||||
"LoanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent",
|
"LoanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent",
|
||||||
"LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent", "LoanTransactionContractTerminationPostBusinessEvent",
|
"LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent", "LoanTransactionContractTerminationPostBusinessEvent",
|
||||||
"LoanCapitalizedIncomeAmortizationAdjustmentTransactionCreatedBusinessEvent");
|
"LoanCapitalizedIncomeAmortizationAdjustmentTransactionCreatedBusinessEvent",
|
||||||
|
"LoanCapitalizedIncomeTransactionCreatedBusinessEvent");
|
||||||
|
|
||||||
List<FineractPlatformTenant> tenants = Arrays
|
List<FineractPlatformTenant> tenants = Arrays
|
||||||
.asList(new FineractPlatformTenant(1L, "default", "Default Tenant", "Europe/Budapest", null));
|
.asList(new FineractPlatformTenant(1L, "default", "Default Tenant", "Europe/Budapest", null));
|
||||||
@@ -197,7 +198,8 @@ public class ExternalEventConfigurationValidationServiceTest {
|
|||||||
"LoanTransactionInterestRefundPreBusinessEvent", "LoanAccrualAdjustmentTransactionBusinessEvent",
|
"LoanTransactionInterestRefundPreBusinessEvent", "LoanAccrualAdjustmentTransactionBusinessEvent",
|
||||||
"LoanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent",
|
"LoanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent",
|
||||||
"LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent", "LoanTransactionContractTerminationPostBusinessEvent",
|
"LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent", "LoanTransactionContractTerminationPostBusinessEvent",
|
||||||
"LoanCapitalizedIncomeAmortizationAdjustmentTransactionCreatedBusinessEvent");
|
"LoanCapitalizedIncomeAmortizationAdjustmentTransactionCreatedBusinessEvent",
|
||||||
|
"LoanCapitalizedIncomeTransactionCreatedBusinessEvent");
|
||||||
|
|
||||||
List<FineractPlatformTenant> tenants = Arrays
|
List<FineractPlatformTenant> tenants = Arrays
|
||||||
.asList(new FineractPlatformTenant(1L, "default", "Default Tenant", "Europe/Budapest", null));
|
.asList(new FineractPlatformTenant(1L, "default", "Default Tenant", "Europe/Budapest", null));
|
||||||
|
|||||||
+42
-1
@@ -87,6 +87,7 @@ import org.apache.fineract.client.models.RetrieveLoansPointInTimeRequest;
|
|||||||
import org.apache.fineract.client.util.CallFailedRuntimeException;
|
import org.apache.fineract.client.util.CallFailedRuntimeException;
|
||||||
import org.apache.fineract.client.util.Calls;
|
import org.apache.fineract.client.util.Calls;
|
||||||
import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants;
|
import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants;
|
||||||
|
import org.apache.fineract.infrastructure.event.external.service.validation.ExternalEventDTO;
|
||||||
import org.apache.fineract.integrationtests.client.IntegrationTest;
|
import org.apache.fineract.integrationtests.client.IntegrationTest;
|
||||||
import org.apache.fineract.integrationtests.common.BatchHelper;
|
import org.apache.fineract.integrationtests.common.BatchHelper;
|
||||||
import org.apache.fineract.integrationtests.common.BusinessDateHelper;
|
import org.apache.fineract.integrationtests.common.BusinessDateHelper;
|
||||||
@@ -99,6 +100,9 @@ import org.apache.fineract.integrationtests.common.accounting.AccountHelper;
|
|||||||
import org.apache.fineract.integrationtests.common.accounting.JournalEntryHelper;
|
import org.apache.fineract.integrationtests.common.accounting.JournalEntryHelper;
|
||||||
import org.apache.fineract.integrationtests.common.charges.ChargesHelper;
|
import org.apache.fineract.integrationtests.common.charges.ChargesHelper;
|
||||||
import org.apache.fineract.integrationtests.common.error.ErrorResponse;
|
import org.apache.fineract.integrationtests.common.error.ErrorResponse;
|
||||||
|
import org.apache.fineract.integrationtests.common.externalevents.BusinessEvent;
|
||||||
|
import org.apache.fineract.integrationtests.common.externalevents.ExternalEventHelper;
|
||||||
|
import org.apache.fineract.integrationtests.common.externalevents.ExternalEventsExtension;
|
||||||
import org.apache.fineract.integrationtests.common.loans.LoanAccountLockHelper;
|
import org.apache.fineract.integrationtests.common.loans.LoanAccountLockHelper;
|
||||||
import org.apache.fineract.integrationtests.common.loans.LoanProductHelper;
|
import org.apache.fineract.integrationtests.common.loans.LoanProductHelper;
|
||||||
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
|
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
|
||||||
@@ -119,7 +123,7 @@ import org.junit.jupiter.api.Assertions;
|
|||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ExtendWith(LoanTestLifecycleExtension.class)
|
@ExtendWith({ LoanTestLifecycleExtension.class, ExternalEventsExtension.class })
|
||||||
public abstract class BaseLoanIntegrationTest extends IntegrationTest {
|
public abstract class BaseLoanIntegrationTest extends IntegrationTest {
|
||||||
|
|
||||||
protected static final String DATETIME_PATTERN = "dd MMMM yyyy";
|
protected static final String DATETIME_PATTERN = "dd MMMM yyyy";
|
||||||
@@ -171,6 +175,7 @@ public abstract class BaseLoanIntegrationTest extends IntegrationTest {
|
|||||||
protected GlobalConfigurationHelper globalConfigurationHelper = new GlobalConfigurationHelper();
|
protected GlobalConfigurationHelper globalConfigurationHelper = new GlobalConfigurationHelper();
|
||||||
protected final CodeHelper codeHelper = new CodeHelper();
|
protected final CodeHelper codeHelper = new CodeHelper();
|
||||||
protected final ChargesHelper chargesHelper = new ChargesHelper();
|
protected final ChargesHelper chargesHelper = new ChargesHelper();
|
||||||
|
protected final ExternalEventHelper externalEventHelper = new ExternalEventHelper();
|
||||||
|
|
||||||
protected static void validateRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, LocalDate dueDate, double principalDue,
|
protected static void validateRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, LocalDate dueDate, double principalDue,
|
||||||
double principalPaid, double principalOutstanding, double paidInAdvance, double paidLate) {
|
double principalPaid, double principalOutstanding, double paidInAdvance, double paidLate) {
|
||||||
@@ -1269,6 +1274,42 @@ public abstract class BaseLoanIntegrationTest extends IntegrationTest {
|
|||||||
new PostLoansLoanIdRequest().rejectedOnDate(rejectedOnDate).locale("en").dateFormat(DATETIME_PATTERN));
|
new PostLoansLoanIdRequest().rejectedOnDate(rejectedOnDate).locale("en").dateFormat(DATETIME_PATTERN));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void verifyBusinessEvents(BusinessEvent... businessEvents) {
|
||||||
|
List<ExternalEventDTO> allExternalEvents = ExternalEventHelper.getAllExternalEvents(requestSpec, responseSpec);
|
||||||
|
logBusinessEvents(allExternalEvents);
|
||||||
|
Assertions.assertNotNull(businessEvents);
|
||||||
|
Assertions.assertNotNull(allExternalEvents);
|
||||||
|
Assertions.assertTrue(businessEvents.length <= allExternalEvents.size(),
|
||||||
|
"Expected business event count is less than actual. Expected: " + businessEvents.length + " Actual: "
|
||||||
|
+ allExternalEvents.size());
|
||||||
|
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATETIME_PATTERN, Locale.ENGLISH);
|
||||||
|
for (BusinessEvent businessEvent : businessEvents) {
|
||||||
|
long count = allExternalEvents.stream().filter(externalEvent -> businessEvent.verify(externalEvent, formatter)).count();
|
||||||
|
Assertions.assertEquals(1, count, "Expected business event not found " + businessEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void logBusinessEvents(List<ExternalEventDTO> allExternalEvents) {
|
||||||
|
allExternalEvents.forEach(externalEventDTO -> {
|
||||||
|
Object amount = externalEventDTO.getPayLoad().get("amount");
|
||||||
|
Object outstandingLoanBalance = externalEventDTO.getPayLoad().get("outstandingLoanBalance");
|
||||||
|
Object principalPortion = externalEventDTO.getPayLoad().get("principalPortion");
|
||||||
|
Object interestPortion = externalEventDTO.getPayLoad().get("interestPortion");
|
||||||
|
Object feePortion = externalEventDTO.getPayLoad().get("feeChargesPortion");
|
||||||
|
Object penaltyPortion = externalEventDTO.getPayLoad().get("penaltyChargesPortion");
|
||||||
|
log.info("Event Received\n type:'{}'\n businessDate:'{}'", externalEventDTO.getType(), externalEventDTO.getBusinessDate());
|
||||||
|
log.info(
|
||||||
|
"Values\n amount: {}\n outstandingLoanBalance: {}\n principalPortion: {}\n interestPortion: {}\n feePortion: {}\n penaltyPortion: {}",
|
||||||
|
amount, outstandingLoanBalance, principalPortion, interestPortion, feePortion, penaltyPortion);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void deleteAllExternalEvents() {
|
||||||
|
ExternalEventHelper.deleteAllExternalEvents(requestSpec, createResponseSpecification(Matchers.is(204)));
|
||||||
|
List<ExternalEventDTO> allExternalEvents = ExternalEventHelper.getAllExternalEvents(requestSpec, responseSpec);
|
||||||
|
Assertions.assertEquals(0, allExternalEvents.size());
|
||||||
|
}
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public static class BatchRequestBuilder {
|
public static class BatchRequestBuilder {
|
||||||
|
|
||||||
|
|||||||
-7
@@ -37,7 +37,6 @@ import org.apache.fineract.integrationtests.common.SchedulerJobHelper;
|
|||||||
import org.apache.fineract.integrationtests.common.externalevents.ExternalEventHelper;
|
import org.apache.fineract.integrationtests.common.externalevents.ExternalEventHelper;
|
||||||
import org.apache.fineract.integrationtests.common.externalevents.ExternalEventsExtension;
|
import org.apache.fineract.integrationtests.common.externalevents.ExternalEventsExtension;
|
||||||
import org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension;
|
import org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension;
|
||||||
import org.hamcrest.Matchers;
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
@@ -305,12 +304,6 @@ public class CustomSnapshotEventIntegrationTest extends BaseLoanIntegrationTest
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteAllExternalEvents() {
|
|
||||||
ExternalEventHelper.deleteAllExternalEvents(requestSpec, createResponseSpecification(Matchers.is(204)));
|
|
||||||
List<ExternalEventDTO> allExternalEvents = ExternalEventHelper.getAllExternalEvents(requestSpec, responseSpec);
|
|
||||||
Assertions.assertEquals(0, allExternalEvents.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void enableCOBBusinessStep(String... steps) {
|
private void enableCOBBusinessStep(String... steps) {
|
||||||
new BusinessStepHelper().updateSteps("LOAN_CLOSE_OF_BUSINESS", steps);
|
new BusinessStepHelper().updateSteps("LOAN_CLOSE_OF_BUSINESS", steps);
|
||||||
|
|
||||||
|
|||||||
+3
-250
@@ -25,24 +25,12 @@ import io.restassured.builder.ResponseSpecBuilder;
|
|||||||
import io.restassured.http.ContentType;
|
import io.restassured.http.ContentType;
|
||||||
import io.restassured.specification.RequestSpecification;
|
import io.restassured.specification.RequestSpecification;
|
||||||
import io.restassured.specification.ResponseSpecification;
|
import io.restassured.specification.ResponseSpecification;
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||||
import org.apache.fineract.client.models.GetLoansLoanIdStatus;
|
import org.apache.fineract.client.models.GetLoansLoanIdStatus;
|
||||||
import org.apache.fineract.client.models.GlobalConfigurationPropertyData;
|
import org.apache.fineract.client.models.GlobalConfigurationPropertyData;
|
||||||
@@ -66,8 +54,10 @@ import org.apache.fineract.integrationtests.common.LoanRescheduleRequestHelper;
|
|||||||
import org.apache.fineract.integrationtests.common.Utils;
|
import org.apache.fineract.integrationtests.common.Utils;
|
||||||
import org.apache.fineract.integrationtests.common.externalevents.ExternalEventHelper;
|
import org.apache.fineract.integrationtests.common.externalevents.ExternalEventHelper;
|
||||||
import org.apache.fineract.integrationtests.common.externalevents.ExternalEventsExtension;
|
import org.apache.fineract.integrationtests.common.externalevents.ExternalEventsExtension;
|
||||||
|
import org.apache.fineract.integrationtests.common.externalevents.LoanAdjustTransactionBusinessEvent;
|
||||||
|
import org.apache.fineract.integrationtests.common.externalevents.LoanBusinessEvent;
|
||||||
|
import org.apache.fineract.integrationtests.common.externalevents.LoanTransactionBusinessEvent;
|
||||||
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
|
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
|
||||||
import org.hamcrest.Matchers;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
@@ -1012,12 +1002,6 @@ public class ExternalBusinessEventTest extends BaseLoanIntegrationTest {
|
|||||||
externalEventHelper.disableBusinessEvent("LoanBalanceChangedBusinessEvent");
|
externalEventHelper.disableBusinessEvent("LoanBalanceChangedBusinessEvent");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteAllExternalEvents() {
|
|
||||||
ExternalEventHelper.deleteAllExternalEvents(requestSpec, createResponseSpecification(Matchers.is(204)));
|
|
||||||
List<ExternalEventDTO> allExternalEvents = ExternalEventHelper.getAllExternalEvents(requestSpec, responseSpec);
|
|
||||||
Assertions.assertEquals(0, allExternalEvents.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Long createLoanProductPeriodicWithInterest() {
|
private static Long createLoanProductPeriodicWithInterest() {
|
||||||
String name = Utils.uniqueRandomStringGenerator("LOAN_PRODUCT_", 6);
|
String name = Utils.uniqueRandomStringGenerator("LOAN_PRODUCT_", 6);
|
||||||
String shortName = Utils.uniqueRandomStringGenerator("", 4);
|
String shortName = Utils.uniqueRandomStringGenerator("", 4);
|
||||||
@@ -1070,21 +1054,6 @@ public class ExternalBusinessEventTest extends BaseLoanIntegrationTest {
|
|||||||
return loanId;
|
return loanId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logBusinessEvents(List<ExternalEventDTO> allExternalEvents) {
|
|
||||||
allExternalEvents.forEach(externalEventDTO -> {
|
|
||||||
Object amount = externalEventDTO.getPayLoad().get("amount");
|
|
||||||
Object outstandingLoanBalance = externalEventDTO.getPayLoad().get("outstandingLoanBalance");
|
|
||||||
Object principalPortion = externalEventDTO.getPayLoad().get("principalPortion");
|
|
||||||
Object interestPortion = externalEventDTO.getPayLoad().get("interestPortion");
|
|
||||||
Object feePortion = externalEventDTO.getPayLoad().get("feeChargesPortion");
|
|
||||||
Object penaltyPortion = externalEventDTO.getPayLoad().get("penaltyChargesPortion");
|
|
||||||
log.info("Event Received\n type:'{}'\n businessDate:'{}'", externalEventDTO.getType(), externalEventDTO.getBusinessDate());
|
|
||||||
log.info(
|
|
||||||
"Values\n amount: {}\n outstandingLoanBalance: {}\n principalPortion: {}\n interestPortion: {}\n feePortion: {}\n penaltyPortion: {}",
|
|
||||||
amount, outstandingLoanBalance, principalPortion, interestPortion, feePortion, penaltyPortion);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void enableLoanInterestRefundPstBusinessEvent(boolean enabled) {
|
private void enableLoanInterestRefundPstBusinessEvent(boolean enabled) {
|
||||||
externalEventHelper.configureBusinessEvent("LoanTransactionInterestRefundPostBusinessEvent", enabled);
|
externalEventHelper.configureBusinessEvent("LoanTransactionInterestRefundPostBusinessEvent", enabled);
|
||||||
}
|
}
|
||||||
@@ -1096,220 +1065,4 @@ public class ExternalBusinessEventTest extends BaseLoanIntegrationTest {
|
|||||||
private void configureLoanAccrualTransactionCreatedBusinessEvent(boolean enabled) {
|
private void configureLoanAccrualTransactionCreatedBusinessEvent(boolean enabled) {
|
||||||
externalEventHelper.configureBusinessEvent("LoanAccrualTransactionCreatedBusinessEvent", enabled);
|
externalEventHelper.configureBusinessEvent("LoanAccrualTransactionCreatedBusinessEvent", enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void verifyBusinessEvents(BusinessEvent... businessEvents) {
|
|
||||||
List<ExternalEventDTO> allExternalEvents = ExternalEventHelper.getAllExternalEvents(requestSpec, responseSpec);
|
|
||||||
logBusinessEvents(allExternalEvents);
|
|
||||||
Assertions.assertNotNull(businessEvents);
|
|
||||||
Assertions.assertNotNull(allExternalEvents);
|
|
||||||
Assertions.assertTrue(businessEvents.length <= allExternalEvents.size(),
|
|
||||||
"Expected business event count is less than actual. Expected: " + businessEvents.length + " Actual: "
|
|
||||||
+ allExternalEvents.size());
|
|
||||||
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATETIME_PATTERN, Locale.ENGLISH);
|
|
||||||
for (BusinessEvent businessEvent : businessEvents) {
|
|
||||||
long count = allExternalEvents.stream().filter(externalEvent -> businessEvent.verify(externalEvent, formatter)).count();
|
|
||||||
Assertions.assertEquals(1, count, "Expected business event not found " + businessEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
@NoArgsConstructor
|
|
||||||
public static class BusinessEvent {
|
|
||||||
|
|
||||||
String type;
|
|
||||||
String businessDate;
|
|
||||||
|
|
||||||
boolean verify(@NotNull ExternalEventDTO externalEvent, DateTimeFormatter formatter) {
|
|
||||||
var businessDate = LocalDate.parse(getBusinessDate(), formatter);
|
|
||||||
|
|
||||||
return Objects.equals(externalEvent.getType(), getType()) && Objects.equals(externalEvent.getBusinessDate(), businessDate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
public static class LoanTransactionBusinessEvent extends BusinessEvent {
|
|
||||||
|
|
||||||
private Double amount;
|
|
||||||
private Double outstandingLoanBalance;
|
|
||||||
private Double principalPortion;
|
|
||||||
private Double interestPortion;
|
|
||||||
private Double feeChargesPortion;
|
|
||||||
private Double penaltyChargesPortion;
|
|
||||||
|
|
||||||
public LoanTransactionBusinessEvent(String type, String businessDate, Double amount, Double outstandingLoanBalance,
|
|
||||||
Double principalPortion, Double interestPortion, Double feeChargesPortion, Double penaltyChargesPortion) {
|
|
||||||
super(type, businessDate);
|
|
||||||
this.amount = amount;
|
|
||||||
this.outstandingLoanBalance = outstandingLoanBalance;
|
|
||||||
this.principalPortion = principalPortion;
|
|
||||||
this.interestPortion = interestPortion;
|
|
||||||
this.feeChargesPortion = feeChargesPortion;
|
|
||||||
this.penaltyChargesPortion = penaltyChargesPortion;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean verify(ExternalEventDTO externalEvent, DateTimeFormatter formatter) {
|
|
||||||
Object amount = externalEvent.getPayLoad().get("amount");
|
|
||||||
Object outstandingLoanBalance = externalEvent.getPayLoad().get("outstandingLoanBalance");
|
|
||||||
Object principalPortion = externalEvent.getPayLoad().get("principalPortion");
|
|
||||||
Object interestPortion = externalEvent.getPayLoad().get("interestPortion");
|
|
||||||
Object feePortion = externalEvent.getPayLoad().get("feeChargesPortion");
|
|
||||||
Object penaltyPortion = externalEvent.getPayLoad().get("penaltyChargesPortion");
|
|
||||||
|
|
||||||
return super.verify(externalEvent, formatter) && Objects.equals(amount, getAmount())
|
|
||||||
&& Objects.equals(outstandingLoanBalance, getOutstandingLoanBalance())
|
|
||||||
&& Objects.equals(principalPortion, getPrincipalPortion()) && Objects.equals(interestPortion, getInterestPortion())
|
|
||||||
&& Objects.equals(feePortion, getFeeChargesPortion()) && Objects.equals(penaltyPortion, getPenaltyChargesPortion());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
public static class LoanBusinessEvent extends BusinessEvent {
|
|
||||||
|
|
||||||
private Integer statusId;
|
|
||||||
private Double principalDisbursed;
|
|
||||||
private Double principalOutstanding;
|
|
||||||
private List<String> loanTermVariationType;
|
|
||||||
|
|
||||||
public LoanBusinessEvent(String type, String businessDate, Integer statusId, Double principalDisbursed,
|
|
||||||
Double principalOutstanding) {
|
|
||||||
super(type, businessDate);
|
|
||||||
this.statusId = statusId;
|
|
||||||
this.principalDisbursed = principalDisbursed;
|
|
||||||
this.principalOutstanding = principalOutstanding;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoanBusinessEvent(String type, String businessDate, Integer statusId, Double principalDisbursed, Double principalOutstanding,
|
|
||||||
List<String> loanTermVariationType) {
|
|
||||||
super(type, businessDate);
|
|
||||||
this.statusId = statusId;
|
|
||||||
this.principalDisbursed = principalDisbursed;
|
|
||||||
this.principalOutstanding = principalOutstanding;
|
|
||||||
this.loanTermVariationType = loanTermVariationType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean verify(ExternalEventDTO externalEvent, DateTimeFormatter formatter) {
|
|
||||||
Object summaryRes = externalEvent.getPayLoad().get("summary");
|
|
||||||
Object statusRes = externalEvent.getPayLoad().get("status");
|
|
||||||
Map<String, Object> summary = summaryRes instanceof Map ? (Map<String, Object>) summaryRes : Map.of();
|
|
||||||
Map<String, Object> status = statusRes instanceof Map ? (Map<String, Object>) statusRes : Map.of();
|
|
||||||
var principalDisbursed = summary.get("principalDisbursed");
|
|
||||||
|
|
||||||
var principalOutstanding = summary.get("principalOutstanding");
|
|
||||||
Double statusId = (Double) status.get("id");
|
|
||||||
return super.verify(externalEvent, formatter) && Objects.equals(statusId, getStatusId().doubleValue())
|
|
||||||
&& Objects.equals(principalDisbursed, getPrincipalDisbursed())
|
|
||||||
&& Objects.equals(principalOutstanding, getPrincipalOutstanding()) && loanTermVariationsMatch(
|
|
||||||
(List<Map<String, Object>>) externalEvent.getPayLoad().get("loanTermVariations"), loanTermVariationType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean loanTermVariationsMatch(final List<Map<String, Object>> loanTermVariations, final List<String> expectedTypes) {
|
|
||||||
if (CollectionUtils.isEmpty(expectedTypes)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
final long numberOfMatches = expectedTypes.stream().filter(expectedType -> loanTermVariations.stream().anyMatch(
|
|
||||||
variation -> StringUtils.equals((String) ((Map<String, Object>) variation.get("termType")).get("value"), expectedType)))
|
|
||||||
.count();
|
|
||||||
|
|
||||||
return numberOfMatches == expectedTypes.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class LoanAdjustTransactionBusinessEvent extends BusinessEvent {
|
|
||||||
|
|
||||||
private String transactionTypeCode;
|
|
||||||
private String transactionDate;
|
|
||||||
private Double oldAmount;
|
|
||||||
private Double newAmount;
|
|
||||||
private Double oldPrincipalPortion;
|
|
||||||
private Double newPrincipalPortion;
|
|
||||||
private Double oldInterestPortion;
|
|
||||||
private Double newInterestPortion;
|
|
||||||
private Double oldFeePortion;
|
|
||||||
private Double newFeePortion;
|
|
||||||
private Double oldPenaltyPortion;
|
|
||||||
private Double newPenaltyPortion;
|
|
||||||
|
|
||||||
public LoanAdjustTransactionBusinessEvent(String type, String businessDate, String transactionTypeCode, String transactionDate) {
|
|
||||||
super(type, businessDate);
|
|
||||||
this.transactionTypeCode = transactionTypeCode;
|
|
||||||
this.transactionDate = transactionDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoanAdjustTransactionBusinessEvent(String type, String businessDate, String transactionTypeCode, String transactionDate,
|
|
||||||
Double oldAmount, Double newAmount) {
|
|
||||||
super(type, businessDate);
|
|
||||||
this.transactionTypeCode = transactionTypeCode;
|
|
||||||
this.transactionDate = transactionDate;
|
|
||||||
this.oldAmount = oldAmount;
|
|
||||||
this.newAmount = newAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoanAdjustTransactionBusinessEvent(String type, String businessDate, String transactionTypeCode, String transactionDate,
|
|
||||||
Double oldAmount, Double newAmount, Double oldPrincipalPortion, Double newPrincipalPortion, Double oldInterestPortion,
|
|
||||||
Double newInterestPortion, Double oldFeePortion, Double newFeePortion, Double oldPenaltyPortion, Double newPenaltyPortion) {
|
|
||||||
super(type, businessDate);
|
|
||||||
this.transactionTypeCode = transactionTypeCode;
|
|
||||||
this.transactionDate = transactionDate;
|
|
||||||
this.oldAmount = oldAmount;
|
|
||||||
this.newAmount = newAmount;
|
|
||||||
this.oldPrincipalPortion = oldPrincipalPortion;
|
|
||||||
this.newPrincipalPortion = newPrincipalPortion;
|
|
||||||
this.oldInterestPortion = oldInterestPortion;
|
|
||||||
this.newInterestPortion = newInterestPortion;
|
|
||||||
this.oldFeePortion = oldFeePortion;
|
|
||||||
this.newFeePortion = newFeePortion;
|
|
||||||
this.oldPenaltyPortion = oldPenaltyPortion;
|
|
||||||
this.newPenaltyPortion = newPenaltyPortion;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean verify(ExternalEventDTO externalEvent, DateTimeFormatter formatter) {
|
|
||||||
final Object transactionToAdjust = externalEvent.getPayLoad().get("transactionToAdjust");
|
|
||||||
final Map<?, Object> transActionToAdjustMap = transactionToAdjust instanceof Map ? (Map<String, Object>) transactionToAdjust
|
|
||||||
: Collections.emptyMap();
|
|
||||||
|
|
||||||
Object actualOldAmount = transActionToAdjustMap.get("amount");
|
|
||||||
Object actualOldPrincipalPortion = transActionToAdjustMap.get("principalPortion");
|
|
||||||
Object actualOldInterestPortion = transActionToAdjustMap.get("interestPortion");
|
|
||||||
Object actualOldFeePortion = transActionToAdjustMap.get("feeChargesPortion");
|
|
||||||
Object actualOldPenaltyPortion = transActionToAdjustMap.get("penaltyChargesPortion");
|
|
||||||
|
|
||||||
final Object newTransactionDetail = externalEvent.getPayLoad().get("newTransactionDetail");
|
|
||||||
final Map<?, Object> newTransactionDetailMap = newTransactionDetail instanceof Map ? (Map<String, Object>) newTransactionDetail
|
|
||||||
: Collections.emptyMap();
|
|
||||||
|
|
||||||
Object actualNewAmount = newTransactionDetailMap.get("amount");
|
|
||||||
Object actualNewPrincipalPortion = newTransactionDetailMap.get("principalPortion");
|
|
||||||
Object actualNewInterestPortion = newTransactionDetailMap.get("interestPortion");
|
|
||||||
Object actualNewFeePortion = newTransactionDetailMap.get("feeChargesPortion");
|
|
||||||
Object actualNewPenaltyPortion = newTransactionDetailMap.get("penaltyChargesPortion");
|
|
||||||
|
|
||||||
final Object actualTransactionDate = transActionToAdjustMap.get("date");
|
|
||||||
final Object transactionType = transActionToAdjustMap.get("type");
|
|
||||||
final Map<?, Object> transactionTypeMap = transactionType instanceof Map ? (Map<String, Object>) transactionType
|
|
||||||
: Collections.emptyMap();
|
|
||||||
final Object actualTransactionTypeCode = transactionTypeMap.get("code");
|
|
||||||
|
|
||||||
return super.verify(externalEvent, formatter)//
|
|
||||||
&& Objects.equals(actualTransactionTypeCode, transactionTypeCode)
|
|
||||||
&& Objects.equals(actualTransactionDate, transactionDate)//
|
|
||||||
&& (oldAmount == null || Objects.equals(actualOldAmount, oldAmount))//
|
|
||||||
&& (newAmount == null || Objects.equals(actualNewAmount, newAmount))//
|
|
||||||
&& (oldPrincipalPortion == null || Objects.equals(actualOldPrincipalPortion, oldPrincipalPortion))//
|
|
||||||
&& (newPrincipalPortion == null || Objects.equals(actualNewPrincipalPortion, newPrincipalPortion))//
|
|
||||||
&& (oldInterestPortion == null || Objects.equals(actualOldInterestPortion, oldInterestPortion))//
|
|
||||||
&& (newInterestPortion == null || Objects.equals(actualNewInterestPortion, newInterestPortion))//
|
|
||||||
&& (oldFeePortion == null || Objects.equals(actualOldFeePortion, oldFeePortion))//
|
|
||||||
&& (newFeePortion == null || Objects.equals(actualNewFeePortion, newFeePortion))//
|
|
||||||
&& (oldPenaltyPortion == null || Objects.equals(actualOldPenaltyPortion, oldPenaltyPortion))//
|
|
||||||
&& (newPenaltyPortion == null || Objects.equals(actualNewPenaltyPortion, newPenaltyPortion));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+113
@@ -36,6 +36,9 @@ import org.apache.fineract.client.models.PostLoansResponse;
|
|||||||
import org.apache.fineract.client.util.CallFailedRuntimeException;
|
import org.apache.fineract.client.util.CallFailedRuntimeException;
|
||||||
import org.apache.fineract.integrationtests.common.BusinessStepHelper;
|
import org.apache.fineract.integrationtests.common.BusinessStepHelper;
|
||||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||||
|
import org.apache.fineract.integrationtests.common.externalevents.LoanAdjustTransactionBusinessEvent;
|
||||||
|
import org.apache.fineract.integrationtests.common.externalevents.LoanBusinessEvent;
|
||||||
|
import org.apache.fineract.integrationtests.common.externalevents.LoanTransactionBusinessEvent;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@@ -780,4 +783,114 @@ public class LoanCapitalizedIncomeTest extends BaseLoanIntegrationTest {
|
|||||||
Assertions.assertEquals(thousandFiveHundred, loanDetails.getSummary().getTotalPrincipal().setScale(1, RoundingMode.HALF_UP));
|
Assertions.assertEquals(thousandFiveHundred, loanDetails.getSummary().getTotalPrincipal().setScale(1, RoundingMode.HALF_UP));
|
||||||
Assertions.assertEquals(zero, loanDetails.getSummary().getPrincipalOutstanding().setScale(0, RoundingMode.HALF_UP));
|
Assertions.assertEquals(zero, loanDetails.getSummary().getPrincipalOutstanding().setScale(0, RoundingMode.HALF_UP));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCapitalizedIncomeEvents() {
|
||||||
|
externalEventHelper.enableBusinessEvent("LoanCapitalizedIncomeTransactionCreatedBusinessEvent");
|
||||||
|
externalEventHelper.enableBusinessEvent("LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent");
|
||||||
|
externalEventHelper.enableBusinessEvent("LoanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent");
|
||||||
|
externalEventHelper.enableBusinessEvent("LoanCapitalizedIncomeAmortizationAdjustmentTransactionCreatedBusinessEvent");
|
||||||
|
externalEventHelper.enableBusinessEvent("LoanAdjustTransactionBusinessEvent");
|
||||||
|
externalEventHelper.enableBusinessEvent("LoanBalanceChangedBusinessEvent");
|
||||||
|
|
||||||
|
final AtomicReference<Long> loanIdRef = new AtomicReference<>();
|
||||||
|
final AtomicReference<Long> capitalizedIncomeTransactionIdRef = new AtomicReference<>();
|
||||||
|
|
||||||
|
final PostClientsResponse client = clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
|
||||||
|
|
||||||
|
final PostLoanProductsResponse loanProductsResponse = loanProductHelper
|
||||||
|
.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true)
|
||||||
|
.capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT)
|
||||||
|
.capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION)
|
||||||
|
.deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue())
|
||||||
|
.incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue())
|
||||||
|
.capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE));
|
||||||
|
|
||||||
|
runAt("1 January 2024", () -> {
|
||||||
|
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProductsResponse.getResourceId(), "1 January 2024",
|
||||||
|
500.0, 7.0, 3, null);
|
||||||
|
loanIdRef.set(loanId);
|
||||||
|
|
||||||
|
disburseLoan(loanId, BigDecimal.valueOf(100), "1 January 2024");
|
||||||
|
|
||||||
|
deleteAllExternalEvents();
|
||||||
|
|
||||||
|
Long capitalizedIncomeTransactionId = loanTransactionHelper.addCapitalizedIncome(loanId, "1 January 2024", 100.0)
|
||||||
|
.getResourceId();
|
||||||
|
capitalizedIncomeTransactionIdRef.set(capitalizedIncomeTransactionId);
|
||||||
|
|
||||||
|
verifyBusinessEvents(
|
||||||
|
new LoanTransactionBusinessEvent("LoanCapitalizedIncomeTransactionCreatedBusinessEvent", "01 January 2024", 100.0,
|
||||||
|
200.0, 100.0, 0.0, 0.0, 0.0),
|
||||||
|
new LoanBusinessEvent("LoanBalanceChangedBusinessEvent", "01 January 2024", 300, 100.0, 200.0));
|
||||||
|
});
|
||||||
|
runAt("2 January 2024", () -> {
|
||||||
|
Long loanId = loanIdRef.get();
|
||||||
|
|
||||||
|
deleteAllExternalEvents();
|
||||||
|
|
||||||
|
executeInlineCOB(loanId);
|
||||||
|
|
||||||
|
verifyTransactions(loanId, //
|
||||||
|
transaction(100.0, "Disbursement", "01 January 2024"), //
|
||||||
|
transaction(100.0, "Capitalized Income", "01 January 2024"), //
|
||||||
|
transaction(1.10, "Capitalized Income Amortization", "01 January 2024") //
|
||||||
|
);
|
||||||
|
verifyBusinessEvents(new LoanTransactionBusinessEvent("LoanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent",
|
||||||
|
"01 January 2024", 1.10, 0.0, 0.0, 0.0, 1.10, 0.0));
|
||||||
|
});
|
||||||
|
runAt("3 January 2024", () -> {
|
||||||
|
Long loanId = loanIdRef.get();
|
||||||
|
executeInlineCOB(loanId);
|
||||||
|
|
||||||
|
deleteAllExternalEvents();
|
||||||
|
|
||||||
|
Long capitalizedIncomeAdjustmentTransactionId = loanTransactionHelper
|
||||||
|
.capitalizedIncomeAdjustment(loanId, capitalizedIncomeTransactionIdRef.get(), "3 January 2024", 50.0).getResourceId();
|
||||||
|
|
||||||
|
verifyTransactions(loanId, //
|
||||||
|
transaction(100.0, "Disbursement", "01 January 2024"), //
|
||||||
|
transaction(100.0, "Capitalized Income", "01 January 2024"), //
|
||||||
|
transaction(1.10, "Capitalized Income Amortization", "01 January 2024"), //
|
||||||
|
transaction(0.04, "Accrual", "02 January 2024"), //
|
||||||
|
transaction(1.10, "Capitalized Income Amortization", "02 January 2024"), //
|
||||||
|
transaction(50.0, "Capitalized Income Adjustment", "03 January 2024") //
|
||||||
|
);
|
||||||
|
|
||||||
|
verifyBusinessEvents(
|
||||||
|
new LoanTransactionBusinessEvent("LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent", "03 January 2024",
|
||||||
|
50.0, 150.0, 50.0, 0.0, 0.0, 0.0),
|
||||||
|
new LoanBusinessEvent("LoanBalanceChangedBusinessEvent", "03 January 2024", 300, 100.0, 150.0));
|
||||||
|
|
||||||
|
deleteAllExternalEvents();
|
||||||
|
|
||||||
|
loanTransactionHelper.reverseLoanTransaction(loanId, capitalizedIncomeAdjustmentTransactionId, "3 January 2024");
|
||||||
|
|
||||||
|
verifyBusinessEvents(new LoanAdjustTransactionBusinessEvent("LoanAdjustTransactionBusinessEvent", "03 January 2024",
|
||||||
|
"loanTransactionType.capitalizedIncomeAdjustment", "2024-01-03"));
|
||||||
|
});
|
||||||
|
runAt("4 January 2024", () -> {
|
||||||
|
Long loanId = loanIdRef.get();
|
||||||
|
executeInlineCOB(loanId);
|
||||||
|
|
||||||
|
deleteAllExternalEvents();
|
||||||
|
|
||||||
|
loanTransactionHelper.reverseLoanTransaction(loanId, capitalizedIncomeTransactionIdRef.get(), "3 January 2024");
|
||||||
|
|
||||||
|
verifyTransactions(loanId, //
|
||||||
|
transaction(100.0, "Disbursement", "01 January 2024"), //
|
||||||
|
transaction(100.0, "Capitalized Income", "01 January 2024"), //
|
||||||
|
transaction(1.10, "Capitalized Income Amortization", "01 January 2024"), //
|
||||||
|
transaction(0.04, "Accrual", "02 January 2024"), //
|
||||||
|
transaction(1.10, "Capitalized Income Amortization", "02 January 2024"), //
|
||||||
|
transaction(0.04, "Accrual", "03 January 2024"), //
|
||||||
|
transaction(1.10, "Capitalized Income Amortization", "02 January 2024"), //
|
||||||
|
transaction(50.0, "Capitalized Income Adjustment", "03 January 2024") //
|
||||||
|
);
|
||||||
|
|
||||||
|
verifyBusinessEvents(new LoanAdjustTransactionBusinessEvent("LoanAdjustTransactionBusinessEvent", "04 January 2024",
|
||||||
|
"loanTransactionType.capitalizedIncome", "2024-01-01") //
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -606,6 +606,11 @@ public class ExternalEventConfigurationHelper {
|
|||||||
loanCapitalizedIncomeAmortizationAdjustmentTransactionCreatedBusinessEvent.put("enabled", false);
|
loanCapitalizedIncomeAmortizationAdjustmentTransactionCreatedBusinessEvent.put("enabled", false);
|
||||||
defaults.add(loanCapitalizedIncomeAmortizationAdjustmentTransactionCreatedBusinessEvent);
|
defaults.add(loanCapitalizedIncomeAmortizationAdjustmentTransactionCreatedBusinessEvent);
|
||||||
|
|
||||||
|
Map<String, Object> loanCapitalizedIncomeTransactionCreatedBusinessEvent = new HashMap<>();
|
||||||
|
loanCapitalizedIncomeTransactionCreatedBusinessEvent.put("type", "LoanCapitalizedIncomeTransactionCreatedBusinessEvent");
|
||||||
|
loanCapitalizedIncomeTransactionCreatedBusinessEvent.put("enabled", false);
|
||||||
|
defaults.add(loanCapitalizedIncomeTransactionCreatedBusinessEvent);
|
||||||
|
|
||||||
return defaults;
|
return defaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* 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.integrationtests.common.externalevents;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Objects;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.apache.fineract.infrastructure.event.external.service.validation.ExternalEventDTO;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class BusinessEvent {
|
||||||
|
|
||||||
|
protected String type;
|
||||||
|
protected String businessDate;
|
||||||
|
|
||||||
|
public boolean verify(@NotNull ExternalEventDTO externalEvent, DateTimeFormatter formatter) {
|
||||||
|
var businessDate = LocalDate.parse(getBusinessDate(), formatter);
|
||||||
|
|
||||||
|
return Objects.equals(externalEvent.getType(), getType()) && Objects.equals(externalEvent.getBusinessDate(), businessDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
+122
@@ -0,0 +1,122 @@
|
|||||||
|
/**
|
||||||
|
* 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.integrationtests.common.externalevents;
|
||||||
|
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.apache.fineract.infrastructure.event.external.service.validation.ExternalEventDTO;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
public class LoanAdjustTransactionBusinessEvent extends BusinessEvent {
|
||||||
|
|
||||||
|
private String transactionTypeCode;
|
||||||
|
private String transactionDate;
|
||||||
|
private Double oldAmount;
|
||||||
|
private Double newAmount;
|
||||||
|
private Double oldPrincipalPortion;
|
||||||
|
private Double newPrincipalPortion;
|
||||||
|
private Double oldInterestPortion;
|
||||||
|
private Double newInterestPortion;
|
||||||
|
private Double oldFeePortion;
|
||||||
|
private Double newFeePortion;
|
||||||
|
private Double oldPenaltyPortion;
|
||||||
|
private Double newPenaltyPortion;
|
||||||
|
|
||||||
|
// minimum data for checking if transaction was reversed
|
||||||
|
public LoanAdjustTransactionBusinessEvent(String type, String businessDate, String transactionTypeCode, String transactionDate) {
|
||||||
|
super(type, businessDate);
|
||||||
|
this.transactionTypeCode = transactionTypeCode;
|
||||||
|
this.transactionDate = transactionDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// minimum data for checking if transaction was adjusted
|
||||||
|
public LoanAdjustTransactionBusinessEvent(String type, String businessDate, String transactionTypeCode, String transactionDate,
|
||||||
|
Double oldAmount, Double newAmount) {
|
||||||
|
super(type, businessDate);
|
||||||
|
this.transactionTypeCode = transactionTypeCode;
|
||||||
|
this.transactionDate = transactionDate;
|
||||||
|
this.oldAmount = oldAmount;
|
||||||
|
this.newAmount = newAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanAdjustTransactionBusinessEvent(String type, String businessDate, String transactionTypeCode, String transactionDate,
|
||||||
|
Double oldAmount, Double newAmount, Double oldPrincipalPortion, Double newPrincipalPortion, Double oldInterestPortion,
|
||||||
|
Double newInterestPortion, Double oldFeePortion, Double newFeePortion, Double oldPenaltyPortion, Double newPenaltyPortion) {
|
||||||
|
super(type, businessDate);
|
||||||
|
this.transactionTypeCode = transactionTypeCode;
|
||||||
|
this.transactionDate = transactionDate;
|
||||||
|
this.oldAmount = oldAmount;
|
||||||
|
this.newAmount = newAmount;
|
||||||
|
this.oldPrincipalPortion = oldPrincipalPortion;
|
||||||
|
this.newPrincipalPortion = newPrincipalPortion;
|
||||||
|
this.oldInterestPortion = oldInterestPortion;
|
||||||
|
this.newInterestPortion = newInterestPortion;
|
||||||
|
this.oldFeePortion = oldFeePortion;
|
||||||
|
this.newFeePortion = newFeePortion;
|
||||||
|
this.oldPenaltyPortion = oldPenaltyPortion;
|
||||||
|
this.newPenaltyPortion = newPenaltyPortion;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean verify(ExternalEventDTO externalEvent, DateTimeFormatter formatter) {
|
||||||
|
final Object transactionToAdjust = externalEvent.getPayLoad().get("transactionToAdjust");
|
||||||
|
final Map<?, Object> transActionToAdjustMap = transactionToAdjust instanceof Map ? (Map<String, Object>) transactionToAdjust
|
||||||
|
: Collections.emptyMap();
|
||||||
|
|
||||||
|
Object actualOldAmount = transActionToAdjustMap.get("amount");
|
||||||
|
Object actualOldPrincipalPortion = transActionToAdjustMap.get("principalPortion");
|
||||||
|
Object actualOldInterestPortion = transActionToAdjustMap.get("interestPortion");
|
||||||
|
Object actualOldFeePortion = transActionToAdjustMap.get("feeChargesPortion");
|
||||||
|
Object actualOldPenaltyPortion = transActionToAdjustMap.get("penaltyChargesPortion");
|
||||||
|
|
||||||
|
final Object newTransactionDetail = externalEvent.getPayLoad().get("newTransactionDetail");
|
||||||
|
final Map<?, Object> newTransactionDetailMap = newTransactionDetail instanceof Map ? (Map<String, Object>) newTransactionDetail
|
||||||
|
: Collections.emptyMap();
|
||||||
|
|
||||||
|
Object actualNewAmount = newTransactionDetailMap.get("amount");
|
||||||
|
Object actualNewPrincipalPortion = newTransactionDetailMap.get("principalPortion");
|
||||||
|
Object actualNewInterestPortion = newTransactionDetailMap.get("interestPortion");
|
||||||
|
Object actualNewFeePortion = newTransactionDetailMap.get("feeChargesPortion");
|
||||||
|
Object actualNewPenaltyPortion = newTransactionDetailMap.get("penaltyChargesPortion");
|
||||||
|
|
||||||
|
final Object actualTransactionDate = transActionToAdjustMap.get("date");
|
||||||
|
final Object transactionType = transActionToAdjustMap.get("type");
|
||||||
|
final Map<?, Object> transactionTypeMap = transactionType instanceof Map ? (Map<String, Object>) transactionType
|
||||||
|
: Collections.emptyMap();
|
||||||
|
final Object actualTransactionTypeCode = transactionTypeMap.get("code");
|
||||||
|
|
||||||
|
return super.verify(externalEvent, formatter)//
|
||||||
|
&& Objects.equals(actualTransactionTypeCode, transactionTypeCode) && Objects.equals(actualTransactionDate, transactionDate)//
|
||||||
|
&& (oldAmount == null || Objects.equals(actualOldAmount, oldAmount))//
|
||||||
|
&& (newAmount == null || Objects.equals(actualNewAmount, newAmount))//
|
||||||
|
&& (oldPrincipalPortion == null || Objects.equals(actualOldPrincipalPortion, oldPrincipalPortion))//
|
||||||
|
&& (newPrincipalPortion == null || Objects.equals(actualNewPrincipalPortion, newPrincipalPortion))//
|
||||||
|
&& (oldInterestPortion == null || Objects.equals(actualOldInterestPortion, oldInterestPortion))//
|
||||||
|
&& (newInterestPortion == null || Objects.equals(actualNewInterestPortion, newInterestPortion))//
|
||||||
|
&& (oldFeePortion == null || Objects.equals(actualOldFeePortion, oldFeePortion))//
|
||||||
|
&& (newFeePortion == null || Objects.equals(actualNewFeePortion, newFeePortion))//
|
||||||
|
&& (oldPenaltyPortion == null || Objects.equals(actualOldPenaltyPortion, oldPenaltyPortion))//
|
||||||
|
&& (newPenaltyPortion == null || Objects.equals(actualNewPenaltyPortion, newPenaltyPortion));
|
||||||
|
}
|
||||||
|
}
|
||||||
+85
@@ -0,0 +1,85 @@
|
|||||||
|
/**
|
||||||
|
* 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.integrationtests.common.externalevents;
|
||||||
|
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.fineract.infrastructure.event.external.service.validation.ExternalEventDTO;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
public class LoanBusinessEvent extends BusinessEvent {
|
||||||
|
|
||||||
|
private Integer statusId;
|
||||||
|
private Double principalDisbursed;
|
||||||
|
private Double principalOutstanding;
|
||||||
|
private List<String> loanTermVariationType;
|
||||||
|
|
||||||
|
public LoanBusinessEvent(String type, String businessDate, Integer statusId, Double principalDisbursed, Double principalOutstanding) {
|
||||||
|
super(type, businessDate);
|
||||||
|
this.statusId = statusId;
|
||||||
|
this.principalDisbursed = principalDisbursed;
|
||||||
|
this.principalOutstanding = principalOutstanding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanBusinessEvent(String type, String businessDate, Integer statusId, Double principalDisbursed, Double principalOutstanding,
|
||||||
|
List<String> loanTermVariationType) {
|
||||||
|
super(type, businessDate);
|
||||||
|
this.statusId = statusId;
|
||||||
|
this.principalDisbursed = principalDisbursed;
|
||||||
|
this.principalOutstanding = principalOutstanding;
|
||||||
|
this.loanTermVariationType = loanTermVariationType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean verify(ExternalEventDTO externalEvent, DateTimeFormatter formatter) {
|
||||||
|
Object summaryRes = externalEvent.getPayLoad().get("summary");
|
||||||
|
Object statusRes = externalEvent.getPayLoad().get("status");
|
||||||
|
Map<String, Object> summary = summaryRes instanceof Map ? (Map<String, Object>) summaryRes : Map.of();
|
||||||
|
Map<String, Object> status = statusRes instanceof Map ? (Map<String, Object>) statusRes : Map.of();
|
||||||
|
var principalDisbursed = summary.get("principalDisbursed");
|
||||||
|
|
||||||
|
var principalOutstanding = summary.get("principalOutstanding");
|
||||||
|
Double statusId = (Double) status.get("id");
|
||||||
|
return super.verify(externalEvent, formatter) && Objects.equals(statusId, getStatusId().doubleValue())
|
||||||
|
&& Objects.equals(principalDisbursed, getPrincipalDisbursed())
|
||||||
|
&& Objects.equals(principalOutstanding, getPrincipalOutstanding()) && loanTermVariationsMatch(
|
||||||
|
(List<Map<String, Object>>) externalEvent.getPayLoad().get("loanTermVariations"), loanTermVariationType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean loanTermVariationsMatch(final List<Map<String, Object>> loanTermVariations, final List<String> expectedTypes) {
|
||||||
|
if (CollectionUtils.isEmpty(expectedTypes)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
final long numberOfMatches = expectedTypes
|
||||||
|
.stream().filter(
|
||||||
|
expectedType -> loanTermVariations.stream()
|
||||||
|
.anyMatch(variation -> StringUtils
|
||||||
|
.equals((String) ((Map<String, Object>) variation.get("termType")).get("value"), expectedType)))
|
||||||
|
.count();
|
||||||
|
|
||||||
|
return numberOfMatches == expectedTypes.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* 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.integrationtests.common.externalevents;
|
||||||
|
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Objects;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.apache.fineract.infrastructure.event.external.service.validation.ExternalEventDTO;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
public class LoanTransactionBusinessEvent extends BusinessEvent {
|
||||||
|
|
||||||
|
private Double amount;
|
||||||
|
private Double outstandingLoanBalance;
|
||||||
|
private Double principalPortion;
|
||||||
|
private Double interestPortion;
|
||||||
|
private Double feeChargesPortion;
|
||||||
|
private Double penaltyChargesPortion;
|
||||||
|
|
||||||
|
public LoanTransactionBusinessEvent(String type, String businessDate, Double amount, Double outstandingLoanBalance,
|
||||||
|
Double principalPortion, Double interestPortion, Double feeChargesPortion, Double penaltyChargesPortion) {
|
||||||
|
super(type, businessDate);
|
||||||
|
this.amount = amount;
|
||||||
|
this.outstandingLoanBalance = outstandingLoanBalance;
|
||||||
|
this.principalPortion = principalPortion;
|
||||||
|
this.interestPortion = interestPortion;
|
||||||
|
this.feeChargesPortion = feeChargesPortion;
|
||||||
|
this.penaltyChargesPortion = penaltyChargesPortion;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean verify(ExternalEventDTO externalEvent, DateTimeFormatter formatter) {
|
||||||
|
Object amount = externalEvent.getPayLoad().get("amount");
|
||||||
|
Object outstandingLoanBalance = externalEvent.getPayLoad().get("outstandingLoanBalance");
|
||||||
|
Object principalPortion = externalEvent.getPayLoad().get("principalPortion");
|
||||||
|
Object interestPortion = externalEvent.getPayLoad().get("interestPortion");
|
||||||
|
Object feePortion = externalEvent.getPayLoad().get("feeChargesPortion");
|
||||||
|
Object penaltyPortion = externalEvent.getPayLoad().get("penaltyChargesPortion");
|
||||||
|
|
||||||
|
return super.verify(externalEvent, formatter) && Objects.equals(amount, getAmount())
|
||||||
|
&& Objects.equals(outstandingLoanBalance, getOutstandingLoanBalance())
|
||||||
|
&& Objects.equals(principalPortion, getPrincipalPortion()) && Objects.equals(interestPortion, getInterestPortion())
|
||||||
|
&& Objects.equals(feePortion, getFeeChargesPortion()) && Objects.equals(penaltyPortion, getPenaltyChargesPortion());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user