FINERACT-2107: Interest Refund - Allocation, Business Event & Full Repayment

This commit is contained in:
Soma Sörös
2024-10-21 17:36:20 +02:00
committed by Adam Saghy
parent 84d606552d
commit 5722891477
18 changed files with 969 additions and 77 deletions
@@ -76,7 +76,6 @@ import org.apache.fineract.integrationtests.common.accounting.PeriodicAccrualAcc
import org.apache.fineract.integrationtests.common.charges.ChargesHelper;
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.EarlyPaymentLoanRepaymentScheduleTransactionProcessor;
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.FineractStyleLoanRepaymentScheduleTransactionProcessor;
@@ -4426,7 +4425,7 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
.interestRatePerPeriod(5.0).interestCalculationPeriodType(DAYS).interestRateFrequencyType(YEARS)
.daysInMonthType(DaysInMonthType.DAYS_30.getValue()).daysInYearType(DaysInYearType.DAYS_360).numberOfRepayments(5)//
.daysInMonthType(DaysInMonthType.DAYS_30).daysInYearType(DaysInYearType.DAYS_360).numberOfRepayments(5)//
.repaymentEvery(1)//
.repaymentFrequencyType(2L)//
.enableDownPayment(true)//
@@ -4488,7 +4487,7 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
.interestRatePerPeriod(12.3).interestCalculationPeriodType(RepaymentFrequencyType.DAYS).interestRateFrequencyType(YEARS)
.daysInMonthType(DaysInMonthType.DAYS_30.getValue()).daysInYearType(DaysInYearType.DAYS_360).numberOfRepayments(5)//
.daysInMonthType(DaysInMonthType.DAYS_30).daysInYearType(DaysInYearType.DAYS_360).numberOfRepayments(5)//
.repaymentEvery(1)//
.repaymentFrequencyType(2L)//
.enableDownPayment(true)//
@@ -4551,7 +4550,7 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
.interestRatePerPeriod(12.3).interestCalculationPeriodType(RepaymentFrequencyType.DAYS).interestRateFrequencyType(YEARS)
.daysInMonthType(DaysInMonthType.DAYS_30.getValue()).daysInYearType(DaysInYearType.DAYS_360).numberOfRepayments(5)//
.daysInMonthType(DaysInMonthType.DAYS_30).daysInYearType(DaysInYearType.DAYS_360).numberOfRepayments(5)//
.repaymentEvery(1)//
.repaymentFrequencyType(2L)//
.enableDownPayment(true)//
@@ -4614,7 +4613,7 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
.interestRatePerPeriod(12.3).interestCalculationPeriodType(RepaymentFrequencyType.DAYS).interestRateFrequencyType(YEARS)
.daysInMonthType(DaysInMonthType.ACTUAL.getValue()).daysInYearType(DaysInYearType.DAYS_365).numberOfRepayments(4)//
.daysInMonthType(DaysInMonthType.ACTUAL).daysInYearType(DaysInYearType.DAYS_365).numberOfRepayments(4)//
.repaymentEvery(1)//
.repaymentFrequencyType(2L)//
.allowPartialPeriodInterestCalcualtion(false)//
@@ -4692,8 +4691,8 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
.interestRatePerPeriod(108.0).interestCalculationPeriodType(RepaymentFrequencyType.DAYS)
.interestRateFrequencyType(YEARS).daysInMonthType(DaysInMonthType.ACTUAL.getValue())
.daysInYearType(DaysInYearType.DAYS_360).numberOfRepayments(4)//
.interestRateFrequencyType(YEARS).daysInMonthType(DaysInMonthType.ACTUAL).daysInYearType(DaysInYearType.DAYS_360)
.numberOfRepayments(4)//
.maxInterestRatePerPeriod((double) 110)//
.repaymentEvery(1)//
.repaymentFrequencyType(1L)//
@@ -4873,7 +4872,7 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
interestRefundTypes.add("MERCHANT_ISSUED_REFUND");
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
.interestRatePerPeriod(12.0).interestCalculationPeriodType(RepaymentFrequencyType.DAYS).interestRateFrequencyType(YEARS)
.daysInMonthType(DaysInMonthType.ACTUAL.getValue()).daysInYearType(DaysInYearType.DAYS_365).numberOfRepayments(4)//
.daysInMonthType(DaysInMonthType.ACTUAL).daysInYearType(DaysInYearType.DAYS_365).numberOfRepayments(4)//
.repaymentEvery(5)//
.repaymentFrequencyType(0L)//
.allowPartialPeriodInterestCalcualtion(false)//
@@ -4935,8 +4934,8 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
.interestRatePerPeriod(interestRatePerPeriod.doubleValue()).interestCalculationPeriodType(RepaymentFrequencyType.DAYS)
.interestRateFrequencyType(YEARS).daysInMonthType(DaysInMonthType.DAYS_30.getValue())
.daysInYearType(DaysInYearType.DAYS_360).numberOfRepayments(6)//
.interestRateFrequencyType(YEARS).daysInMonthType(DaysInMonthType.DAYS_30).daysInYearType(DaysInYearType.DAYS_360)
.numberOfRepayments(6)//
.repaymentEvery(1)//
.repaymentFrequencyType(2L)//
.enableDownPayment(false)//
@@ -5017,8 +5016,8 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
.interestRatePerPeriod(interestRatePerPeriod.doubleValue()).interestCalculationPeriodType(RepaymentFrequencyType.DAYS)
.interestRateFrequencyType(YEARS).daysInMonthType(DaysInMonthType.DAYS_30.getValue())
.daysInYearType(DaysInYearType.DAYS_360).numberOfRepayments(6)//
.interestRateFrequencyType(YEARS).daysInMonthType(DaysInMonthType.DAYS_30).daysInYearType(DaysInYearType.DAYS_360)
.numberOfRepayments(6)//
.repaymentEvery(1)//
.repaymentFrequencyType(2L)//
.enableDownPayment(false)//
@@ -5114,7 +5113,7 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
.interestRatePerPeriod(interestRatePerPeriod.doubleValue())//
.interestCalculationPeriodType(RepaymentFrequencyType.DAYS)//
.interestRateFrequencyType(YEARS)//
.daysInMonthType(DaysInMonthType.DAYS_30.getValue())//
.daysInMonthType(DaysInMonthType.DAYS_30)//
.daysInYearType(DaysInYearType.DAYS_360)//
.numberOfRepayments(6)//
.repaymentEvery(1)//
@@ -1281,6 +1281,13 @@ public abstract class BaseLoanIntegrationTest {
public static final Integer DAYS_365 = 365;
}
public static class DaysInMonthType {
public static final Integer INVALID = 0;
public static final Integer ACTUAL = 1;
public static final Integer DAYS_30 = 30;
}
public static class FuturePaymentAllocationRule {
public static final String LAST_INSTALLMENT = "LAST_INSTALLMENT";
@@ -25,9 +25,11 @@ import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.http.ContentType;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -35,6 +37,8 @@ import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@@ -42,6 +46,8 @@ import org.apache.fineract.client.models.PostClientsResponse;
import org.apache.fineract.client.models.PostCreateRescheduleLoansRequest;
import org.apache.fineract.client.models.PostCreateRescheduleLoansResponse;
import org.apache.fineract.client.models.PostLoanProductsRequest;
import org.apache.fineract.client.models.PostLoanProductsResponse;
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
import org.apache.fineract.client.models.PostLoansRequest;
import org.apache.fineract.client.models.PostUpdateRescheduleLoansRequest;
import org.apache.fineract.infrastructure.event.external.service.validation.ExternalEventDTO;
@@ -111,7 +117,7 @@ public class ExternalBusinessEventTest extends BaseLoanIntegrationTest {
loanTransactionHelper.makeLoanRepayment("15 March 2023", 125.0F, loanIdRef.get().intValue());
verifyBusinessEvents(new BusinessEvent("LoanBalanceChangedBusinessEvent", "15 March 2023", 300, 400.0, 291.04));
verifyBusinessEvents(new LoanBusinessEvent("LoanBalanceChangedBusinessEvent", "15 March 2023", 300, 400.0, 291.04));
});
runAt("1 April 2023", () -> {
@@ -123,7 +129,7 @@ public class ExternalBusinessEventTest extends BaseLoanIntegrationTest {
loanTransactionHelper.makeLoanRepayment("15 April 2023", 125.0F, loanIdRef.get().intValue());
verifyBusinessEvents(new BusinessEvent("LoanBalanceChangedBusinessEvent", "15 April 2023", 300, 1000.0, 770.06));
verifyBusinessEvents(new LoanBusinessEvent("LoanBalanceChangedBusinessEvent", "15 April 2023", 300, 1000.0, 770.06));
deleteAllExternalEvents();
@@ -131,24 +137,57 @@ public class ExternalBusinessEventTest extends BaseLoanIntegrationTest {
.getResourceId();
Assertions.assertNotNull(transactionId);
verifyBusinessEvents(new BusinessEvent("LoanBalanceChangedBusinessEvent", "15 April 2023", 700, 1000.0, 0.0));
verifyBusinessEvents(new LoanBusinessEvent("LoanBalanceChangedBusinessEvent", "15 April 2023", 700, 1000.0, 0.0));
deleteAllExternalEvents();
loanTransactionHelper.reverseRepayment(loanIdRef.get().intValue(), transactionId.intValue(), "15 April 2023");
verifyBusinessEvents(new BusinessEvent("LoanBalanceChangedBusinessEvent", "15 April 2023", 300, 1000.0, 770.06));
verifyBusinessEvents(new LoanBusinessEvent("LoanBalanceChangedBusinessEvent", "15 April 2023", 300, 1000.0, 770.06));
deleteAllExternalEvents();
loanTransactionHelper.makeLoanRepayment("15 April 2023", 830.22F, loanIdRef.get().intValue());
verifyBusinessEvents(new BusinessEvent("LoanBalanceChangedBusinessEvent", "15 April 2023", 600, 1000.0, 0.0));
verifyBusinessEvents(new LoanBusinessEvent("LoanBalanceChangedBusinessEvent", "15 April 2023", 600, 1000.0, 0.0));
disableLoanBalanceChangedBusinessEvent();
});
}
@Test
public void verifyInterestRefundPostBusinessEventCreatedForMerchantIssuedRefundWithInterestRefund() {
AtomicReference<Long> loanIdRef = new AtomicReference<>();
enableLoanInterestRefundPstBusinessEvent(true);
runAt("1 January 2021", () -> {
PostLoanProductsResponse loanProduct = loanProductHelper
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
.daysInYearType(DaysInYearType.ACTUAL) //
.supportedInterestRefundTypes(new ArrayList<>()).addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
.recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
);
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
12, null);
Assertions.assertNotNull(loanId);
loanIdRef.set(loanId);
disburseLoan(loanId, BigDecimal.valueOf(1000), "1 January 2021");
});
runAt("22 January 2021", () -> {
Long loanId = loanIdRef.get();
deleteAllExternalEvents();
PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
.makeLoanRepayment("MerchantIssuedRefund", "22 January 2021", 1000F, loanId.intValue());
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
verifyBusinessEvents(new LoanTransactionBusinessEvent("LoanTransactionInterestRefundPostBusinessEvent", "22 January 2021", 5.75,
994.25, 5.75, 0.0, 0.0, 0.0));
});
enableLoanInterestRefundPstBusinessEvent(false);
}
@Test
public void testExternalBusinessEventLoanRescheduledDueAdjustScheduleBusinessEventInterestChange() {
AtomicReference<Long> loanIdRef = new AtomicReference<>();
@@ -171,7 +210,7 @@ public class ExternalBusinessEventTest extends BaseLoanIntegrationTest {
loanRescheduleRequestHelper.approveLoanRescheduleRequest(rescheduleLoansResponse.getResourceId(),
new PostUpdateRescheduleLoansRequest().approvedOnDate("1 March 2024").locale("en").dateFormat(DATETIME_PATTERN));
verifyBusinessEvents(new BusinessEvent("LoanRescheduledDueAdjustScheduleBusinessEvent", "01 March 2024", 300, 400.0, 400.0,
verifyBusinessEvents(new LoanBusinessEvent("LoanRescheduledDueAdjustScheduleBusinessEvent", "01 March 2024", 300, 400.0, 400.0,
List.of("interestRateForInstallment")));
});
}
@@ -260,11 +299,28 @@ public class ExternalBusinessEventTest extends BaseLoanIntegrationTest {
private void logBusinessEvents(List<ExternalEventDTO> allExternalEvents) {
allExternalEvents.forEach(externalEventDTO -> {
log.info("Event Received { type:'{}' businessDate:'{}' }", externalEventDTO.getType(), externalEventDTO.getBusinessDate());
log.debug(externalEventDTO.toString());
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 static void enableLoanInterestRefundPstBusinessEvent(boolean enabled) {
final Map<String, Boolean> updatedConfigurations = ExternalEventConfigurationHelper.updateExternalEventConfigurations(requestSpec,
responseSpec, "{\"externalEventConfigurations\":{\"LoanTransactionInterestRefundPostBusinessEvent\":"
+ (enabled ? "true" : "false") + "}}\n");
Assertions.assertEquals(updatedConfigurations.size(), 1);
Assertions.assertTrue(updatedConfigurations.containsKey("LoanTransactionInterestRefundPostBusinessEvent"));
Assertions.assertEquals(enabled, updatedConfigurations.get("LoanTransactionInterestRefundPostBusinessEvent"));
}
public void verifyBusinessEvents(BusinessEvent... businessEvents) {
List<ExternalEventDTO> allExternalEvents = ExternalEventHelper.getAllExternalEvents(requestSpec, responseSpec);
logBusinessEvents(allExternalEvents);
@@ -273,61 +329,119 @@ public class ExternalBusinessEventTest extends BaseLoanIntegrationTest {
Assertions.assertTrue(businessEvents.length <= allExternalEvents.size(),
"Expected business event count is less than actual. Expected: " + businessEvents.length + " Actual: "
+ allExternalEvents.size());
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATETIME_PATTERN, Locale.ENGLISH);
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATETIME_PATTERN, Locale.ENGLISH);
for (BusinessEvent businessEvent : businessEvents) {
long count = allExternalEvents.stream().filter(externalEvent -> {
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");
var businessDate = LocalDate.parse(businessEvent.getBusinessDate(), formatter);
Double statusId = (Double) status.get("id");
return Objects.equals(externalEvent.getType(), businessEvent.getType())
&& Objects.equals(externalEvent.getBusinessDate(), businessDate)
&& Objects.equals(statusId, businessEvent.getStatusId().doubleValue())
&& Objects.equals(principalDisbursed, businessEvent.getPrincipalDisbursed())
&& Objects.equals(principalOutstanding, businessEvent.getPrincipalOutstanding())
&& loanTermVariationsMatch((List<Map<String, Object>>) externalEvent.getPayLoad().get("loanTermVariations"),
businessEvent.loanTermVariationType);
}).count();
long count = allExternalEvents.stream().filter(externalEvent -> businessEvent.verify(externalEvent, formatter)).count();
Assertions.assertEquals(1, count, "Expected business event not found " + businessEvent);
}
}
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();
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class BusinessEvent {
public BusinessEvent(String type, String businessDate, Integer statusId, Double principalDisbursed, Double principalOutstanding) {
this.type = type;
this.businessDate = businessDate;
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;
}
private String type;
private String businessDate;
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,
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();
}
}
}
@@ -0,0 +1,412 @@
/**
* 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;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.http.ContentType;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicReference;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
import org.apache.fineract.client.models.PostClientsResponse;
import org.apache.fineract.client.models.PostLoanProductsResponse;
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
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.loans.LoanTransactionHelper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@Slf4j
public class LoanInterestRefundTest extends BaseLoanIntegrationTest {
private static ResponseSpecification responseSpec;
private static RequestSpecification requestSpec;
private static LoanTransactionHelper loanTransactionHelper;
private static PostClientsResponse client;
private static BusinessStepHelper businessStepHelper;
@BeforeAll
public static void setup() {
Utils.initializeRESTAssured();
requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
requestSpec.header("Fineract-Platform-TenantId", "default");
responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec);
ClientHelper clientHelper = new ClientHelper(requestSpec, responseSpec);
client = clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
}
@Test
public void verifyInterestRefundNotCreatedForPayoutRefundWhenTypesAreEmpty() {
AtomicReference<Long> loanIdRef = new AtomicReference<>();
runAt("1 January 2021", () -> {
PostLoanProductsResponse loanProduct = loanProductHelper
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
.daysInYearType(DaysInYearType.ACTUAL) //
.supportedInterestRefundTypes(new ArrayList<>()) //
.recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
);
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.9,
12, null);
Assertions.assertNotNull(loanId);
loanIdRef.set(loanId);
disburseLoan(loanId, BigDecimal.valueOf(1000), "1 January 2021");
});
runAt("22 January 2021", () -> {
Long loanId = loanIdRef.get();
PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
.makeLoanRepayment("PayoutRefund", "22 January 2021", 1000F, loanId.intValue());
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
logTransactions(loanId);
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
transaction(1000.0, "Payout Refund", "22 January 2021"));
});
}
@Test
public void verifyInterestRefundNotCreatedForMerchantIssuedRefundWhenTypesAreEmpty() {
AtomicReference<Long> loanIdRef = new AtomicReference<>();
runAt("1 January 2021", () -> {
PostLoanProductsResponse loanProduct = loanProductHelper
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
.daysInYearType(DaysInYearType.ACTUAL) //
.supportedInterestRefundTypes(new ArrayList<>())//
.recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
);
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.9,
12, null);
Assertions.assertNotNull(loanId);
loanIdRef.set(loanId);
disburseLoan(loanId, BigDecimal.valueOf(1000), "1 January 2021");
});
runAt("22 January 2021", () -> {
Long loanId = loanIdRef.get();
PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
.makeLoanRepayment("MerchantIssuedRefund", "22 January 2021", 1000F, loanId.intValue());
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
logTransactions(loanId);
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
transaction(1000.0, "Merchant Issued Refund", "22 January 2021"));
});
}
@Test
public void verifyInterestRefundCreatedForPayoutRefund() {
AtomicReference<Long> loanIdRef = new AtomicReference<>();
runAt("1 January 2021", () -> {
PostLoanProductsResponse loanProduct = loanProductHelper
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
.daysInYearType(DaysInYearType.ACTUAL) //
.supportedInterestRefundTypes(new ArrayList<>()).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
.recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
);
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
12, null);
Assertions.assertNotNull(loanId);
loanIdRef.set(loanId);
disburseLoan(loanId, BigDecimal.valueOf(1000), "1 January 2021");
});
runAt("22 January 2021", () -> {
Long loanId = loanIdRef.get();
PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
.makeLoanRepayment("PayoutRefund", "22 January 2021", 1000F, loanId.intValue());
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
logTransactions(loanId);
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
transaction(1000.0, "Payout Refund", "22 January 2021"), transaction(5.75, "Accrual", "22 January 2021"),
transaction(5.75, "Interest Refund", "22 January 2021"));
});
}
@Test
public void verifyInterestRefundCreatedForMerchantIssuedRefund() {
AtomicReference<Long> loanIdRef = new AtomicReference<>();
runAt("1 January 2021", () -> {
PostLoanProductsResponse loanProduct = loanProductHelper
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
.daysInYearType(DaysInYearType.ACTUAL) //
.supportedInterestRefundTypes(new ArrayList<>()).addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
.recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
);
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
12, null);
Assertions.assertNotNull(loanId);
loanIdRef.set(loanId);
disburseLoan(loanId, BigDecimal.valueOf(1000), "1 January 2021");
});
runAt("22 January 2021", () -> {
Long loanId = loanIdRef.get();
PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
.makeLoanRepayment("MerchantIssuedRefund", "22 January 2021", 1000F, loanId.intValue());
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
logTransactions(loanId);
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
transaction(1000.0, "Merchant Issued Refund", "22 January 2021"), transaction(5.75, "Accrual", "22 January 2021"),
transaction(5.75, "Interest Refund", "22 January 2021"));
});
}
@Test
public void verifyUC01() {
AtomicReference<Long> loanIdRef = new AtomicReference<>();
runAt("1 January 2021", () -> {
PostLoanProductsResponse loanProduct = loanProductHelper
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
.daysInYearType(DaysInYearType.ACTUAL) //
.supportedInterestRefundTypes(new ArrayList<>()).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
.addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
.recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
);
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
12, null);
Assertions.assertNotNull(loanId);
loanIdRef.set(loanId);
disburseLoan(loanId, BigDecimal.valueOf(1000), "1 January 2021");
});
runAt("22 January 2021", () -> {
Long loanId = loanIdRef.get();
PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
.makeLoanRepayment("PayoutRefund", "22 January 2021", 1000F, loanId.intValue());
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
logTransactions(loanId);
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
transaction(1000.0, "Payout Refund", "22 January 2021"), transaction(5.75, "Accrual", "22 January 2021"),
transaction(5.75, "Interest Refund", "22 January 2021"));
});
}
@Test
public void verifyUC02a() {
AtomicReference<Long> loanIdRef = new AtomicReference<>();
runAt("1 January 2021", () -> {
PostLoanProductsResponse loanProduct = loanProductHelper
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
.daysInYearType(DaysInYearType.ACTUAL) //
.supportedInterestRefundTypes(new ArrayList<>()).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
.addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
.recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
);
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
12, null);
Assertions.assertNotNull(loanId);
loanIdRef.set(loanId);
disburseLoan(loanId, BigDecimal.valueOf(1000), "1 January 2021");
});
runAt("1 February 2021", () -> {
Long loanId = loanIdRef.get();
PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
.makeLoanRepayment("PayoutRefund", "1 February 2021", 1000F, loanId.intValue());
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
logTransactions(loanId);
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
transaction(1000.0, "Payout Refund", "01 February 2021"), transaction(8.48, "Accrual", "01 February 2021"),
transaction(8.48, "Interest Refund", "01 February 2021"));
});
}
@Test
public void verifyUC02b() {
AtomicReference<Long> loanIdRef = new AtomicReference<>();
runAt("1 January 2021", () -> {
PostLoanProductsResponse loanProduct = loanProductHelper
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
.daysInYearType(DaysInYearType.ACTUAL) //
.supportedInterestRefundTypes(new ArrayList<>()).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
.addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
.recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
);
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
12, null);
Assertions.assertNotNull(loanId);
loanIdRef.set(loanId);
disburseLoan(loanId, BigDecimal.valueOf(1000), "1 January 2021");
});
runAt("1 February 2021", () -> {
Long loanId = loanIdRef.get();
PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper.makeLoanRepayment("Repayment",
"1 February 2021", 87.89F, loanId.intValue());
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
logTransactions(loanId);
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
transaction(87.89, "Repayment", "01 February 2021"));
});
runAt("9 February 2021", () -> {
Long loanId = loanIdRef.get();
PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
.makeLoanRepayment("PayoutRefund", "9 February 2021", 1000F, loanId.intValue());
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
logTransactions(loanId);
verifyTransactions(loanId, transaction(1000.0, "Disbursement", "01 January 2021"),
transaction(1000.0, "Payout Refund", "09 February 2021"), transaction(87.89, "Repayment", "01 February 2021"),
transaction(10.50, "Interest Refund", "09 February 2021"));
});
}
@Test
public void verifyUC03() {
AtomicReference<Long> loanIdRef = new AtomicReference<>();
runAt("1 January 2021", () -> {
PostLoanProductsResponse loanProduct = loanProductHelper
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
.daysInYearType(DaysInYearType.ACTUAL) //
.supportedInterestRefundTypes(new ArrayList<>())//
.disallowExpectedDisbursements(true)//
.multiDisburseLoan(true)//
.maxTrancheCount(2).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
.addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
.recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
);
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
12, null);
Assertions.assertNotNull(loanId);
loanIdRef.set(loanId);
disburseLoan(loanId, BigDecimal.valueOf(750), "1 January 2021");
disburseLoan(loanId, BigDecimal.valueOf(250), "1 January 2021");
});
runAt("22 January 2021", () -> {
Long loanId = loanIdRef.get();
PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
.makeLoanRepayment("PayoutRefund", "22 January 2021", 1000F, loanId.intValue());
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
logTransactions(loanId);
verifyTransactions(loanId, transaction(750.0, "Disbursement", "01 January 2021"),
transaction(250.0, "Disbursement", "01 January 2021"), transaction(1000.0, "Payout Refund", "22 January 2021"),
transaction(5.75, "Accrual", "22 January 2021"), transaction(5.75, "Interest Refund", "22 January 2021"));
});
}
@Test
public void verifyUC04() {
AtomicReference<Long> loanIdRef = new AtomicReference<>();
runAt("1 January 2021", () -> {
PostLoanProductsResponse loanProduct = loanProductHelper
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
.daysInYearType(DaysInYearType.ACTUAL) //
.supportedInterestRefundTypes(new ArrayList<>()).disallowExpectedDisbursements(true).multiDisburseLoan(true)
.maxTrancheCount(2).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
.addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
.recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
);
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
12, null);
Assertions.assertNotNull(loanId);
loanIdRef.set(loanId);
disburseLoan(loanId, BigDecimal.valueOf(250), "1 January 2021");
});
runAt("4 January 2021", () -> {
Long loanId = loanIdRef.get();
disburseLoan(loanId, BigDecimal.valueOf(750), "4 January 2021");
});
runAt("22 January 2021", () -> {
Long loanId = loanIdRef.get();
PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
.makeLoanRepayment("PayoutRefund", "22 January 2021", 1000F, loanId.intValue());
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
logTransactions(loanId);
verifyTransactions(loanId, transaction(750.0, "Disbursement", "04 January 2021"),
transaction(250.0, "Disbursement", "01 January 2021"), transaction(1000.0, "Payout Refund", "22 January 2021"),
transaction(5.14, "Accrual", "22 January 2021"), transaction(5.14, "Interest Refund", "22 January 2021"));
});
}
@Test
public void verifyUC05() {
AtomicReference<Long> loanIdRef = new AtomicReference<>();
runAt("1 January 2021", () -> {
PostLoanProductsResponse loanProduct = loanProductHelper
.createLoanProduct(create4IProgressive().daysInMonthType(DaysInMonthType.ACTUAL) //
.daysInYearType(DaysInYearType.ACTUAL) //
.supportedInterestRefundTypes(new ArrayList<>()).disallowExpectedDisbursements(true).multiDisburseLoan(true)
.maxTrancheCount(2).addSupportedInterestRefundTypesItem("PAYOUT_REFUND") //
.addSupportedInterestRefundTypesItem("MERCHANT_ISSUED_REFUND") //
.recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY) //
);
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProduct.getResourceId(), "1 January 2021", 1000.0, 9.99,
12, null);
Assertions.assertNotNull(loanId);
loanIdRef.set(loanId);
disburseLoan(loanId, BigDecimal.valueOf(500), "1 January 2021");
});
runAt("7 January 2021", () -> {
Long loanId = loanIdRef.get();
disburseLoan(loanId, BigDecimal.valueOf(500), "7 January 2021");
});
runAt("1 February 2021", () -> {
Long loanId = loanIdRef.get();
PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper.makeLoanRepayment("Repayment",
"1 February 2021", 87.82F, loanId.intValue());
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
logTransactions(loanId);
verifyTransactions(loanId, transaction(500.0, "Disbursement", "01 January 2021"),
transaction(500.0, "Disbursement", "07 January 2021"), transaction(87.82, "Repayment", "01 February 2021"));
});
runAt("9 February 2021", () -> {
Long loanId = loanIdRef.get();
PostLoansLoanIdTransactionsResponse postLoansLoanIdTransactionsResponse = loanTransactionHelper
.makeLoanRepayment("PayoutRefund", "9 February 2021", 1000F, loanId.intValue());
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse);
Assertions.assertNotNull(postLoansLoanIdTransactionsResponse.getResourceId());
logTransactions(loanId);
verifyTransactions(loanId, transaction(500.0, "Disbursement", "01 January 2021"),
transaction(500.0, "Disbursement", "07 January 2021"), transaction(1000.0, "Payout Refund", "09 February 2021"),
transaction(87.82, "Repayment", "01 February 2021"), transaction(9.67, "Interest Refund", "09 February 2021"));
});
}
private void logTransactions(Long loanId) {
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId.intValue());
assert loanDetails.getTransactions() != null;
loanDetails.getTransactions()
.forEach(tr -> log.info("Transaction {} {} {} ", tr.getType().getValue(), tr.getDate(), tr.getAmount()));
}
}
@@ -44,7 +44,6 @@ import org.apache.fineract.integrationtests.common.Utils;
import org.apache.fineract.integrationtests.common.accounting.AccountHelper;
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
@@ -89,8 +88,8 @@ public class LoanRefundTransactionTest extends BaseLoanIntegrationTest {
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
.interestRatePerPeriod(108.0).interestCalculationPeriodType(RepaymentFrequencyType.DAYS)
.interestRateFrequencyType(YEARS).daysInMonthType(DaysInMonthType.ACTUAL.getValue())
.daysInYearType(DaysInYearType.DAYS_360).numberOfRepayments(4)//
.interestRateFrequencyType(YEARS).daysInMonthType(DaysInMonthType.ACTUAL).daysInYearType(DaysInYearType.DAYS_360)
.numberOfRepayments(4)//
.maxInterestRatePerPeriod((double) 110)//
.repaymentEvery(1)//
.repaymentFrequencyType(1L)//
@@ -161,8 +160,8 @@ public class LoanRefundTransactionTest extends BaseLoanIntegrationTest {
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
.interestRatePerPeriod(108.0).interestCalculationPeriodType(RepaymentFrequencyType.DAYS)
.interestRateFrequencyType(YEARS).daysInMonthType(DaysInMonthType.ACTUAL.getValue())
.daysInYearType(DaysInYearType.DAYS_360).numberOfRepayments(4)//
.interestRateFrequencyType(YEARS).daysInMonthType(DaysInMonthType.ACTUAL).daysInYearType(DaysInYearType.DAYS_360)
.numberOfRepayments(4)//
.maxInterestRatePerPeriod((double) 110)//
.repaymentEvery(1)//
.repaymentFrequencyType(1L)//
@@ -560,6 +560,16 @@ public class ExternalEventConfigurationHelper {
loanTransactionAccrualActivityPreBusinessEvent.put("enabled", false);
defaults.add(loanTransactionAccrualActivityPreBusinessEvent);
Map<String, Object> loanTransactionInterestRefundPostBusinessEvent = new HashMap<>();
loanTransactionInterestRefundPostBusinessEvent.put("type", "LoanTransactionInterestRefundPostBusinessEvent");
loanTransactionInterestRefundPostBusinessEvent.put("enabled", false);
defaults.add(loanTransactionInterestRefundPostBusinessEvent);
Map<String, Object> loanTransactionInterestRefundPreBusinessEvent = new HashMap<>();
loanTransactionInterestRefundPreBusinessEvent.put("type", "LoanTransactionInterestRefundPreBusinessEvent");
loanTransactionInterestRefundPreBusinessEvent.put("enabled", false);
defaults.add(loanTransactionInterestRefundPreBusinessEvent);
return defaults;
}