diff --git a/fineract-loan/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/transaction/LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent.java b/fineract-loan/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/transaction/LoanBuyDownFeeAdjustmentTransactionBusinessEvent.java
similarity index 82%
rename from fineract-loan/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/transaction/LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent.java
rename to fineract-loan/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/transaction/LoanBuyDownFeeAdjustmentTransactionBusinessEvent.java
index ee91f4b17..acd95b459 100644
--- a/fineract-loan/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/transaction/LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent.java
+++ b/fineract-loan/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/transaction/LoanBuyDownFeeAdjustmentTransactionBusinessEvent.java
@@ -20,11 +20,11 @@ package org.apache.fineract.infrastructure.event.business.domain.loan.transactio
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
-public class LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent extends LoanTransactionBusinessEvent {
+public class LoanBuyDownFeeAdjustmentTransactionBusinessEvent extends LoanTransactionBusinessEvent {
- private static final String TYPE = "LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent";
+ private static final String TYPE = "LoanBuyDownFeeAdjustmentTransactionBusinessEvent";
- public LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent(LoanTransaction value) {
+ public LoanBuyDownFeeAdjustmentTransactionBusinessEvent(LoanTransaction value) {
super(value);
}
diff --git a/fineract-loan/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/transaction/LoanBuyDownFeeTransactionCreatedBusinessEvent.java b/fineract-loan/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/transaction/LoanBuyDownFeeTransactionBusinessEvent.java
similarity index 84%
rename from fineract-loan/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/transaction/LoanBuyDownFeeTransactionCreatedBusinessEvent.java
rename to fineract-loan/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/transaction/LoanBuyDownFeeTransactionBusinessEvent.java
index ae9c7497d..0a18e6466 100644
--- a/fineract-loan/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/transaction/LoanBuyDownFeeTransactionCreatedBusinessEvent.java
+++ b/fineract-loan/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/transaction/LoanBuyDownFeeTransactionBusinessEvent.java
@@ -20,11 +20,11 @@ package org.apache.fineract.infrastructure.event.business.domain.loan.transactio
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
-public class LoanBuyDownFeeTransactionCreatedBusinessEvent extends LoanTransactionBusinessEvent {
+public class LoanBuyDownFeeTransactionBusinessEvent extends LoanTransactionBusinessEvent {
- private static final String TYPE = "LoanBuyDownFeeTransactionCreatedBusinessEvent";
+ private static final String TYPE = "LoanBuyDownFeeTransactionBusinessEvent";
- public LoanBuyDownFeeTransactionCreatedBusinessEvent(LoanTransaction value) {
+ public LoanBuyDownFeeTransactionBusinessEvent(LoanTransaction value) {
super(value);
}
diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/BuyDownFeeWritePlatformServiceImpl.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/BuyDownFeeWritePlatformServiceImpl.java
index 8e672f9b9..a285afe02 100644
--- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/BuyDownFeeWritePlatformServiceImpl.java
+++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/BuyDownFeeWritePlatformServiceImpl.java
@@ -36,9 +36,8 @@ import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRu
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
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.LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent;
-import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanBuyDownFeeTransactionCreatedBusinessEvent;
+import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanBuyDownFeeAdjustmentTransactionBusinessEvent;
+import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanBuyDownFeeTransactionBusinessEvent;
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.portfolio.client.domain.Client;
@@ -125,8 +124,7 @@ public class BuyDownFeeWritePlatformServiceImpl implements BuyDownFeePlatformSer
loanJournalEntryPoster.postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
// Notify business events
- businessEventNotifierService.notifyPostBusinessEvent(new LoanBuyDownFeeTransactionCreatedBusinessEvent(buyDownFeeTransaction));
- businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan));
+ businessEventNotifierService.notifyPostBusinessEvent(new LoanBuyDownFeeTransactionBusinessEvent(buyDownFeeTransaction));
return new CommandProcessingResultBuilder() //
.withClientId(loan.getClientId()) //
@@ -205,8 +203,7 @@ public class BuyDownFeeWritePlatformServiceImpl implements BuyDownFeePlatformSer
// Notify business events
businessEventNotifierService
- .notifyPostBusinessEvent(new LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent(savedBuyDownFeeAdjustment));
- businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan));
+ .notifyPostBusinessEvent(new LoanBuyDownFeeAdjustmentTransactionBusinessEvent(savedBuyDownFeeAdjustment));
return new CommandProcessingResultBuilder().withEntityId(savedBuyDownFeeAdjustment.getId())
.withEntityExternalId(savedBuyDownFeeAdjustment.getExternalId()).withOfficeId(loan.getOfficeId())
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/adjustment/LoanAdjustmentServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/adjustment/LoanAdjustmentServiceImpl.java
index d091b57c0..8fd909060 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/adjustment/LoanAdjustmentServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/adjustment/LoanAdjustmentServiceImpl.java
@@ -37,6 +37,9 @@ import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.MathUtil;
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.LoanBuyDownFeeAdjustmentTransactionBusinessEvent;
+import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent;
+import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanBuyDownFeeTransactionBusinessEvent;
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
@@ -321,7 +324,11 @@ public class LoanAdjustmentServiceImpl implements LoanAdjustmentService {
if (optAmortizationAdjustmentTransaction.isPresent()) {
loan.addLoanTransaction(optAmortizationAdjustmentTransaction.get());
loanTransactionRepository.saveAndFlush(optAmortizationAdjustmentTransaction.get());
+ businessEventNotifierService
+ .notifyPostBusinessEvent(new LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent(
+ optAmortizationAdjustmentTransaction.get()));
}
+ businessEventNotifierService.notifyPostBusinessEvent(new LoanBuyDownFeeTransactionBusinessEvent(transactionForAdjustment));
}
if (loan.isClosedWrittenOff()) {
@@ -355,6 +362,8 @@ public class LoanAdjustmentServiceImpl implements LoanAdjustmentService {
MathUtil.nullToZero(buyDownFeeBalance.getUnrecognizedAmount()).add(transactionForAdjustment.getAmount()));
loanBuyDownFeeBalanceRepository.save(buyDownFeeBalance);
}
+ businessEventNotifierService
+ .notifyPostBusinessEvent(new LoanBuyDownFeeAdjustmentTransactionBusinessEvent(transactionForAdjustment));
}
}
diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
index fa8027a4e..81687a9d0 100644
--- a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
+++ b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
@@ -211,4 +211,5 @@
+
diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0193_buy_down_fee_events.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0193_buy_down_fee_events.xml
new file mode 100644
index 000000000..0012376b3
--- /dev/null
+++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0193_buy_down_fee_events.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+ type='LoanBuyDownFeeTransactionCreatedBusinessEvent'
+
+
+
+ type='LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent'
+
+
+
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 697534d2d..e50c35780 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
@@ -110,7 +110,7 @@ public class ExternalEventConfigurationValidationServiceTest {
"LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent", "LoanTransactionContractTerminationPostBusinessEvent",
"LoanCapitalizedIncomeAmortizationAdjustmentTransactionCreatedBusinessEvent",
"LoanCapitalizedIncomeTransactionCreatedBusinessEvent", "LoanUndoContractTerminationBusinessEvent",
- "LoanBuyDownFeeTransactionCreatedBusinessEvent", "LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent",
+ "LoanBuyDownFeeTransactionBusinessEvent", "LoanBuyDownFeeAdjustmentTransactionBusinessEvent",
"LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent",
"LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent", "LoanApprovedAmountChangedBusinessEvent");
@@ -204,7 +204,7 @@ public class ExternalEventConfigurationValidationServiceTest {
"LoanCapitalizedIncomeAdjustmentTransactionCreatedBusinessEvent", "LoanTransactionContractTerminationPostBusinessEvent",
"LoanCapitalizedIncomeAmortizationAdjustmentTransactionCreatedBusinessEvent",
"LoanCapitalizedIncomeTransactionCreatedBusinessEvent", "LoanUndoContractTerminationBusinessEvent",
- "LoanBuyDownFeeTransactionCreatedBusinessEvent", "LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent",
+ "LoanBuyDownFeeTransactionBusinessEvent", "LoanBuyDownFeeAdjustmentTransactionBusinessEvent",
"LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent",
"LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent", "LoanApprovedAmountChangedBusinessEvent");
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java
index 5a92cf5fc..b4d01afd3 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java
@@ -1481,16 +1481,21 @@ public abstract class BaseLoanIntegrationTest extends IntegrationTest {
protected void logBusinessEvents(List 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);
+ if ("org.apache.fineract.avro.loan.v1.LoanTransactionDataV1".equals(externalEventDTO.getSchema())) {
+ 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");
+ Object reversed = externalEventDTO.getPayLoad().get("reversed");
+ log.info(
+ "Values\n amount: {}\n outstandingLoanBalance: {}\n principalPortion: {}\n interestPortion: {}\n feePortion: {}\n penaltyPortion: {}\n reversed: {}",
+ amount, outstandingLoanBalance, principalPortion, interestPortion, feePortion, penaltyPortion, reversed);
+ } else {
+ log.info("Schema: {}", externalEventDTO.getSchema());
+ }
});
}
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanBuyDownFeeTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanBuyDownFeeTest.java
index ad3ecbd9f..54cbbb247 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanBuyDownFeeTest.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanBuyDownFeeTest.java
@@ -47,17 +47,18 @@ import org.apache.fineract.integrationtests.common.BusinessStepHelper;
import org.apache.fineract.integrationtests.common.ClientHelper;
import org.apache.fineract.integrationtests.common.Utils;
import org.apache.fineract.integrationtests.common.accounting.Account;
-import org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension;
+import org.apache.fineract.integrationtests.common.externalevents.BusinessEvent;
+import org.apache.fineract.integrationtests.common.externalevents.ExternalEventHelper;
+import org.apache.fineract.integrationtests.common.externalevents.LoanTransactionMinimalBusinessEvent;
+import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
/**
* Integration tests for Buy Down Fee functionality in Progressive Loans
*/
@Slf4j
-@ExtendWith({ LoanTestLifecycleExtension.class })
public class LoanBuyDownFeeTest extends BaseLoanIntegrationTest {
private Long clientId;
@@ -72,8 +73,21 @@ public class LoanBuyDownFeeTest extends BaseLoanIntegrationTest {
private final Account feeReceivableAccount = accountHelper.createAssetAccount();
private final Account penaltyReceivableAccount = accountHelper.createAssetAccount();
+ @AfterAll
+ public static void teardown() {
+ ExternalEventHelper externalEventHelper = new ExternalEventHelper();
+ externalEventHelper.disableBusinessEvent("LoanBuyDownFeeTransactionBusinessEvent");
+ externalEventHelper.disableBusinessEvent("LoanBuyDownFeeAdjustmentTransactionBusinessEvent");
+ externalEventHelper.disableBusinessEvent("LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent");
+ externalEventHelper.disableBusinessEvent("LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent");
+ }
+
@BeforeEach
public void beforeEach() {
+ externalEventHelper.enableBusinessEvent("LoanBuyDownFeeTransactionBusinessEvent");
+ externalEventHelper.enableBusinessEvent("LoanBuyDownFeeAdjustmentTransactionBusinessEvent");
+ externalEventHelper.enableBusinessEvent("LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent");
+ externalEventHelper.enableBusinessEvent("LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent");
runAt("01 September 2024", () -> {
clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
final PostLoanProductsResponse loanProductsResponse = loanProductHelper
@@ -96,8 +110,10 @@ public class LoanBuyDownFeeTest extends BaseLoanIntegrationTest {
assertNotNull(loanDetailsBeforeTransaction);
log.info("Loan Product: {}", loanDetailsBeforeTransaction.getLoanProductName());
+ deleteAllExternalEvents();
// Create buy down fee transaction
Long buyDownFeeTransactionId = addBuyDownFeeForLoan(loanId, 500.0, "02 September 2024");
+ verifyBusinessEvents(new BusinessEvent("LoanBuyDownFeeTransactionBusinessEvent", "02 September 2024"));
assertNotNull(buyDownFeeTransactionId);
@@ -126,11 +142,14 @@ public class LoanBuyDownFeeTest extends BaseLoanIntegrationTest {
String externalId = UUID.randomUUID().toString();
String noteText = "Buy Down Fee - Test Note";
+ deleteAllExternalEvents();
+
PostLoansLoanIdTransactionsResponse response = loanTransactionHelper.makeLoanBuyDownFee(loanId,
new PostLoansLoanIdTransactionsRequest().dateFormat(DATETIME_PATTERN).transactionDate("03 September 2024").locale("en")
.transactionAmount(250.0).externalId(externalId).note(noteText));
assertNotNull(response.getResourceId());
+ verifyBusinessEvents(new BusinessEvent("LoanBuyDownFeeTransactionBusinessEvent", "03 September 2024"));
// Verify transaction details
final GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
@@ -147,11 +166,17 @@ public class LoanBuyDownFeeTest extends BaseLoanIntegrationTest {
@Test
public void testMultipleBuyDownFees() {
runAt("04 September 2024", () -> {
+ deleteAllExternalEvents();
+
// Add first buy down fee
- Long firstBuyDownFeeId = addBuyDownFeeForLoan(loanId, 200.0, "04 September 2024");
+ Long firstBuyDownFeeId = addBuyDownFeeForLoan(loanId, 200.0, "02 September 2024");
+
+ verifyBusinessEvents(new BusinessEvent("LoanBuyDownFeeTransactionBusinessEvent", "04 September 2024"));
+ deleteAllExternalEvents();
// Add second buy down fee
Long secondBuyDownFeeId = addBuyDownFeeForLoan(loanId, 150.0, "04 September 2024");
+ verifyBusinessEvents(new BusinessEvent("LoanBuyDownFeeTransactionBusinessEvent", "04 September 2024"));
assertNotNull(firstBuyDownFeeId);
assertNotNull(secondBuyDownFeeId);
@@ -258,14 +283,21 @@ public class LoanBuyDownFeeTest extends BaseLoanIntegrationTest {
@Test
public void testBuyDownFeeAdjustment() {
runAt("06 September 2024", () -> {
+ deleteAllExternalEvents();
// Add initial buy down fee
Long buyDownFeeTransactionId = addBuyDownFeeForLoan(loanId, 500.0, "06 September 2024");
assertNotNull(buyDownFeeTransactionId);
+ verifyBusinessEvents(new BusinessEvent("LoanBuyDownFeeTransactionBusinessEvent", "06 September 2024"));
+ deleteAllExternalEvents();
+
// Create buy down fee adjustment (use same date as business date)
PostLoansLoanIdTransactionsResponse adjustmentResponse = loanTransactionHelper.buyDownFeeAdjustment(loanId,
buyDownFeeTransactionId, "06 September 2024", 100.0);
+ verifyBusinessEvents(new LoanTransactionMinimalBusinessEvent("LoanBuyDownFeeAdjustmentTransactionBusinessEvent",
+ "06 September 2024", 100.0, false));
+
assertNotNull(adjustmentResponse);
assertNotNull(adjustmentResponse.getLoanId());
assertNotNull(adjustmentResponse.getClientId());
@@ -286,6 +318,12 @@ public class LoanBuyDownFeeTest extends BaseLoanIntegrationTest {
assertNotNull(adjustmentTransaction);
assertEquals(0, BigDecimal.valueOf(100.0).compareTo(adjustmentTransaction.getAmount()));
assertEquals("06 September 2024", adjustmentTransaction.getDate().format(DateTimeFormatter.ofPattern("dd MMMM yyyy")));
+
+ deleteAllExternalEvents();
+ loanTransactionHelper.reverseLoanTransaction(loanId, adjustmentResponse.getResourceId(), "06 September 2024");
+ verifyBusinessEvents(new LoanTransactionMinimalBusinessEvent("LoanBuyDownFeeAdjustmentTransactionBusinessEvent",
+ "06 September 2024", 100.0, true));
+
});
}
@@ -351,20 +389,30 @@ public class LoanBuyDownFeeTest extends BaseLoanIntegrationTest {
@Test
public void testMultipleBuyDownFeeAdjustments() {
runAt("12 September 2024", () -> {
+ deleteAllExternalEvents();
+
// Add initial buy down fee
Long buyDownFeeTransactionId = addBuyDownFeeForLoan(loanId, 600.0, "12 September 2024");
assertNotNull(buyDownFeeTransactionId);
+ verifyBusinessEvents(new BusinessEvent("LoanBuyDownFeeTransactionBusinessEvent", "12 September 2024"));
+ deleteAllExternalEvents();
+
// First adjustment
PostLoansLoanIdTransactionsResponse adjustment1 = loanTransactionHelper.buyDownFeeAdjustment(loanId, buyDownFeeTransactionId,
"12 September 2024", 100.0);
assertNotNull(adjustment1);
+ verifyBusinessEvents(new BusinessEvent("LoanBuyDownFeeAdjustmentTransactionBusinessEvent", "12 September 2024"));
+ deleteAllExternalEvents();
+
// Second adjustment
PostLoansLoanIdTransactionsResponse adjustment2 = loanTransactionHelper.buyDownFeeAdjustment(loanId, buyDownFeeTransactionId,
"12 September 2024", 150.0);
assertNotNull(adjustment2);
+ verifyBusinessEvents(new BusinessEvent("LoanBuyDownFeeAdjustmentTransactionBusinessEvent", "12 September 2024"));
+
// Verify both adjustments are recorded
final GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
assertNotNull(loanDetails);
@@ -392,10 +440,12 @@ public class LoanBuyDownFeeTest extends BaseLoanIntegrationTest {
@Test
public void testBuyDownFeeAdjustmentWithExternalId() {
runAt("16 September 2024", () -> {
+ deleteAllExternalEvents();
// Add initial buy down fee
Long buyDownFeeTransactionId = addBuyDownFeeForLoan(loanId, 350.0, "16 September 2024");
assertNotNull(buyDownFeeTransactionId);
-
+ verifyBusinessEvents(new BusinessEvent("LoanBuyDownFeeTransactionBusinessEvent", "16 September 2024"));
+ deleteAllExternalEvents();
// Create adjustment with external ID
String adjustmentExternalId = UUID.randomUUID().toString();
PostLoansLoanIdTransactionsResponse adjustmentResponse = loanTransactionHelper.buyDownFeeAdjustment(loanId,
@@ -407,6 +457,8 @@ public class LoanBuyDownFeeTest extends BaseLoanIntegrationTest {
assertNotNull(adjustmentResponse);
assertEquals(adjustmentExternalId, adjustmentResponse.getResourceExternalId());
+ verifyBusinessEvents(new BusinessEvent("LoanBuyDownFeeAdjustmentTransactionBusinessEvent", "16 September 2024"));
+
// Verify adjustment transaction details
final GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId);
GetLoansLoanIdTransactions adjustmentTransaction = loanDetails.getTransactions().stream()
@@ -462,13 +514,17 @@ public class LoanBuyDownFeeTest extends BaseLoanIntegrationTest {
loanIdRef.set(loanId);
disburseLoan(loanId, BigDecimal.valueOf(100), "1 January 2024");
+ deleteAllExternalEvents();
PostLoansLoanIdTransactionsResponse transactionsResponse = loanTransactionHelper.makeLoanBuyDownFee(loanId, "1 January 2024",
50.0);
buyDownFeeTransactionIdIdRef.set(transactionsResponse.getResourceId());
+ verifyBusinessEvents(new BusinessEvent("LoanBuyDownFeeTransactionBusinessEvent", "01 January 2024"));
});
runAt("31 January 2024", () -> {
Long loanId = loanIdRef.get();
+ deleteAllExternalEvents();
executeInlineCOB(loanId);
+ verifyBusinessEvents(new BusinessEvent("LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent", "30 January 2024"));
// summarized amortization
verifyTransactions(loanId, //
@@ -479,7 +535,9 @@ public class LoanBuyDownFeeTest extends BaseLoanIntegrationTest {
});
runAt("1 February 2024", () -> {
Long loanId = loanIdRef.get();
+ deleteAllExternalEvents();
executeInlineCOB(loanId);
+ verifyBusinessEvents(new BusinessEvent("LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent", "31 January 2024"));
// daily amortization
verifyTransactions(loanId, //
@@ -490,11 +548,15 @@ public class LoanBuyDownFeeTest extends BaseLoanIntegrationTest {
transaction(0.01, "Accrual", "31 January 2024"), //
transaction(0.55, "Buy Down Fee Amortization", "31 January 2024"));
+ deleteAllExternalEvents();
loanTransactionHelper.buyDownFeeAdjustment(loanId, buyDownFeeTransactionIdIdRef.get(), "1 February 2024", 10.0);
+ verifyBusinessEvents(new BusinessEvent("LoanBuyDownFeeAdjustmentTransactionBusinessEvent", "01 February 2024"));
});
runAt("2 February 2024", () -> {
Long loanId = loanIdRef.get();
+ deleteAllExternalEvents();
executeInlineCOB(loanId);
+ verifyBusinessEvents(new BusinessEvent("LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent", "01 February 2024"));
// not backdated and not large buy down fee adjustment -> lowered daily amount
verifyTransactions(loanId, //
@@ -508,11 +570,16 @@ public class LoanBuyDownFeeTest extends BaseLoanIntegrationTest {
transaction(0.02, "Accrual", "01 February 2024"), //
transaction(0.39, "Buy Down Fee Amortization", "01 February 2024"));
+ deleteAllExternalEvents();
loanTransactionHelper.buyDownFeeAdjustment(loanId, buyDownFeeTransactionIdIdRef.get(), "10 January 2024", 10.0);
+ verifyBusinessEvents(new BusinessEvent("LoanBuyDownFeeAdjustmentTransactionBusinessEvent", "02 February 2024"));
});
runAt("3 February 2024", () -> {
Long loanId = loanIdRef.get();
+ deleteAllExternalEvents();
executeInlineCOB(loanId);
+ verifyBusinessEvents(
+ new BusinessEvent("LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent", "02 February 2024"));
// backdated buy down fee adjustment -> amortization adjustment
verifyTransactions(loanId, //
@@ -529,11 +596,16 @@ public class LoanBuyDownFeeTest extends BaseLoanIntegrationTest {
transaction(0.02, "Accrual", "02 February 2024"), //
transaction(2.55, "Buy Down Fee Amortization Adjustment", "02 February 2024"));
+ deleteAllExternalEvents();
loanTransactionHelper.buyDownFeeAdjustment(loanId, buyDownFeeTransactionIdIdRef.get(), "03 February 2024", 20.0);
+ verifyBusinessEvents(new BusinessEvent("LoanBuyDownFeeAdjustmentTransactionBusinessEvent", "03 February 2024"));
});
runAt("4 February 2024", () -> {
Long loanId = loanIdRef.get();
+ deleteAllExternalEvents();
executeInlineCOB(loanId);
+ verifyBusinessEvents(
+ new BusinessEvent("LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent", "03 February 2024"));
// large (more than remaining unrecognized (15.13)) buy down fee adjustment -> amortization adjustment
verifyTransactions(loanId, //
@@ -630,7 +702,52 @@ public class LoanBuyDownFeeTest extends BaseLoanIntegrationTest {
}
@Test
- public void testReverseBuyDownFeeTransaction() {
+ public void tesReverseBuyDownFeeTransactionWithAmortizationAdjustmentTransaction() {
+ AtomicReference buyDownFeeTransactionIdRef = new AtomicReference<>();
+ runAt("2 September 2024", () -> {
+ deleteAllExternalEvents();
+ // Add initial buy down fee
+ Long buyDownFeeTransactionId = addBuyDownFeeForLoan(loanId, 400.0, "02 September 2024");
+ buyDownFeeTransactionIdRef.set(buyDownFeeTransactionId);
+ assertNotNull(buyDownFeeTransactionId);
+ verifyBusinessEvents(
+ new LoanTransactionMinimalBusinessEvent("LoanBuyDownFeeTransactionBusinessEvent", "02 September 2024", 400.0, false));
+ });
+ runAt("10 September 2024", () -> {
+ deleteAllExternalEvents();
+ inlineLoanCOBHelper.executeInlineCOB(loanId);
+
+ verifyBusinessEvents(new LoanTransactionMinimalBusinessEvent("LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent",
+ "09 September 2024", 8.79, false));
+
+ deleteAllExternalEvents();
+ Long buyDownFeeTransactionId = buyDownFeeTransactionIdRef.get();
+ // Reverse Buy Down Fee
+ PostLoansLoanIdTransactionsResponse transactionsResponse = loanTransactionHelper.reverseLoanTransaction(loanId,
+ buyDownFeeTransactionId, new PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat(DATETIME_PATTERN)
+ .transactionDate("10 September 2024").note("Buy Down Fee reversed").transactionAmount(0.0).locale("en"));
+ Assertions.assertNotNull(transactionsResponse);
+ Assertions.assertNotNull(transactionsResponse.getResourceId());
+ Assertions.assertEquals(transactionsResponse.getResourceId(), buyDownFeeTransactionId);
+
+ verifyBusinessEvents(
+ new LoanTransactionMinimalBusinessEvent("LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent",
+ "10 September 2024", 8.79, false),
+ new LoanTransactionMinimalBusinessEvent("LoanBuyDownFeeTransactionBusinessEvent", "10 September 2024", 400.0, true));
+
+ verifyTransactions(loanId, //
+ transaction(1000.000000, "Disbursement", "01 September 2024", 1000.000000, 0, 0, 0, 0, 0, 0, false), //
+ transaction(400.000000, "Buy Down Fee", "02 September 2024", 0, 0, 0, 0, 0, 0, 0, true), //
+ transaction(2.220000, "Accrual", "09 September 2024", 0, 0, 2.220000, 0, 0, 0, 0, false), //
+ transaction(8.790000, "Buy Down Fee Amortization", "09 September 2024", 0, 0, 0, 8.790000, 0, 0, 0, false), //
+ transaction(8.790000, "Buy Down Fee Amortization Adjustment", "10 September 2024", 0, 0, 0, 8.790000, 0, 0, 0, false) //
+ );
+
+ });
+ }
+
+ @Test
+ public void testReverseBuyDownFeeTransactionWithoutAmortizationAdjustmentTransaction() {
final AtomicReference buyDownFeeTransactionIdIdRef = new AtomicReference<>();
runAt("10 September 2024", () -> {
@@ -646,11 +763,7 @@ public class LoanBuyDownFeeTest extends BaseLoanIntegrationTest {
verifyTransactions(loanId, //
transaction(1000.0, "Disbursement", "01 September 2024"), //
transaction(400.0, "Buy Down Fee", "10 September 2024"));
- });
- runAt("23 September 2024", () -> {
- final Long buyDownFeeTransactionId = buyDownFeeTransactionIdIdRef.get();
- executeInlineCOB(loanId);
// Reverse Buy Down Fee
PostLoansLoanIdTransactionsResponse transactionsResponse = loanTransactionHelper.reverseLoanTransaction(loanId,
buyDownFeeTransactionId, new PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat(DATETIME_PATTERN)
@@ -659,15 +772,69 @@ public class LoanBuyDownFeeTest extends BaseLoanIntegrationTest {
Assertions.assertNotNull(transactionsResponse.getResourceId());
Assertions.assertEquals(transactionsResponse.getResourceId(), buyDownFeeTransactionId);
+ verifyTransactions(loanId, //
+ transaction(1000.000000, "Disbursement", "01 September 2024", 1000.000000, 0, 0, 0, 0, 0, 0, false), //
+ transaction(400.000000, "Buy Down Fee", "10 September 2024", 0, 0, 0, 0, 0, 0, 0, true) //
+ );
+ });
+ }
+
+ @Test
+ public void testReverseBuyDownFeeTransaction() {
+ final AtomicReference buyDownFeeTransactionIdIdRef = new AtomicReference<>();
+
+ runAt("10 September 2024", () -> {
+ deleteAllExternalEvents();
+ // Add initial buy down fee
+ final Long buyDownFeeTransactionId = addBuyDownFeeForLoan(loanId, 400.0, "10 September 2024");
+ assertNotNull(buyDownFeeTransactionId);
+ buyDownFeeTransactionIdIdRef.set(buyDownFeeTransactionId);
+
+ verifyBusinessEvents(
+ new LoanTransactionMinimalBusinessEvent("LoanBuyDownFeeTransactionBusinessEvent", "10 September 2024", 400.0, false));
+
+ // Verify initial buy down fee accounting entries
+ verifyTRJournalEntries(buyDownFeeTransactionId, debit(buyDownExpenseAccount, 400.0),
+ credit(deferredIncomeLiabilityAccount, 400.0));
+
+ verifyTransactions(loanId, //
+ transaction(1000.0, "Disbursement", "01 September 2024"), //
+ transaction(400.0, "Buy Down Fee", "10 September 2024"));
+ });
+
+ runAt("23 September 2024", () -> {
+ deleteAllExternalEvents();
+ final Long buyDownFeeTransactionId = buyDownFeeTransactionIdIdRef.get();
+ executeInlineCOB(loanId);
+ verifyBusinessEvents(new LoanTransactionMinimalBusinessEvent("LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent",
+ "22 September 2024", 14.61, false));
+
+ deleteAllExternalEvents();
+ // Reverse Buy Down Fee
+ PostLoansLoanIdTransactionsResponse transactionsResponse = loanTransactionHelper.reverseLoanTransaction(loanId,
+ buyDownFeeTransactionId, new PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat(DATETIME_PATTERN)
+ .transactionDate("10 September 2024").note("Buy Down Fee reversed").transactionAmount(0.0).locale("en"));
+ Assertions.assertNotNull(transactionsResponse);
+ Assertions.assertNotNull(transactionsResponse.getResourceId());
+ Assertions.assertEquals(transactionsResponse.getResourceId(), buyDownFeeTransactionId);
+
+ verifyBusinessEvents(
+ new LoanTransactionMinimalBusinessEvent("LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent",
+ "23 September 2024", 14.61, false),
+ new LoanTransactionMinimalBusinessEvent("LoanBuyDownFeeTransactionBusinessEvent", "23 September 2024", 400.0, true));
+
// Verify initial buy down fee reversed accounting entries
verifyTRJournalEntries(buyDownFeeTransactionId, debit(buyDownExpenseAccount, 400.0),
credit(deferredIncomeLiabilityAccount, 400.0), credit(buyDownExpenseAccount, 400.0),
debit(deferredIncomeLiabilityAccount, 400.0));
verifyTransactions(loanId, //
- transaction(1000.0, "Disbursement", "01 September 2024"), //
- reversedTransaction(400.0, "Buy Down Fee", "10 September 2024"), //
- transaction(5.83, "Accrual", "22 September 2024"));
+ transaction(1000.000000, "Disbursement", "01 September 2024", 1000.000000, 0, 0, 0, 0, 0, 0, false), //
+ transaction(400.000000, "Buy Down Fee", "10 September 2024", 0, 0, 0, 0, 0, 0, 0, true), //
+ transaction(5.830000, "Accrual", "22 September 2024", 0, 0, 5.830000, 0, 0, 0, 0, false), //
+ transaction(14.610000, "Buy Down Fee Amortization", "22 September 2024", 0, 0, 0, 14.610000, 0, 0, 0, false), //
+ transaction(14.610000, "Buy Down Fee Amortization Adjustment", "23 September 2024", 0, 0, 0, 14.610000, 0, 0, 0, false) //
+ );
});
}
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 86651e337..41692b743 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
@@ -637,12 +637,12 @@ public class ExternalEventConfigurationHelper {
defaults.add(loanTransactionUndoContractTerminationBusinessEvent);
Map loanTransactionBuyDownFeePostBusinessEvent = new HashMap<>();
- loanTransactionBuyDownFeePostBusinessEvent.put("type", "LoanBuyDownFeeTransactionCreatedBusinessEvent");
+ loanTransactionBuyDownFeePostBusinessEvent.put("type", "LoanBuyDownFeeTransactionBusinessEvent");
loanTransactionBuyDownFeePostBusinessEvent.put("enabled", false);
defaults.add(loanTransactionBuyDownFeePostBusinessEvent);
Map loanTransactionBuyDownFeeAdjustmentPostBusinessEvent = new HashMap<>();
- loanTransactionBuyDownFeeAdjustmentPostBusinessEvent.put("type", "LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent");
+ loanTransactionBuyDownFeeAdjustmentPostBusinessEvent.put("type", "LoanBuyDownFeeAdjustmentTransactionBusinessEvent");
loanTransactionBuyDownFeeAdjustmentPostBusinessEvent.put("enabled", false);
defaults.add(loanTransactionBuyDownFeeAdjustmentPostBusinessEvent);
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/externalevents/LoanTransactionMinimalBusinessEvent.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/externalevents/LoanTransactionMinimalBusinessEvent.java
new file mode 100644
index 000000000..cb6c66e95
--- /dev/null
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/externalevents/LoanTransactionMinimalBusinessEvent.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.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.data.ExternalEventResponse;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class LoanTransactionMinimalBusinessEvent extends BusinessEvent {
+
+ public Double amount;
+ public Boolean reversed;
+
+ public LoanTransactionMinimalBusinessEvent(String type, String businessDate, Double amount, Boolean reversed) {
+ super(type, businessDate);
+ this.amount = amount;
+ this.reversed = reversed;
+ }
+
+ @Override
+ public boolean verify(ExternalEventResponse externalEvent, DateTimeFormatter formatter) {
+ Object actualAmount = externalEvent.getPayLoad().get("amount");
+ Object actualReversed = externalEvent.getPayLoad().get("reversed");
+
+ return super.verify(externalEvent, formatter) && Objects.equals(actualAmount, getAmount())
+ && Objects.equals(actualReversed, getReversed());
+ }
+}