FINERACT-2389: Fix the handling of nullable field overrides
This commit is contained in:
committed by
Adam Saghy
parent
b32837e9b4
commit
adc4ee3545
+2
@@ -170,6 +170,8 @@ public enum DefaultLoanProduct implements LoanProduct {
|
||||
LP1_INTEREST_FLAT_DAILY_RECALCULATION_DAILY_360_30_MULTIDISB, //
|
||||
LP1_INTEREST_FLAT_SAR_RECALCULATION_SAME_AS_REPAYMENT_MULTIDISB_AUTO_DOWNPAYMENT, //
|
||||
LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY, //
|
||||
LP1_WITH_OVERRIDES, //
|
||||
LP1_NO_OVERRIDES //
|
||||
;
|
||||
|
||||
@Override
|
||||
|
||||
+49
@@ -36,6 +36,7 @@ import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.client.models.AdvancedPaymentData;
|
||||
import org.apache.fineract.client.models.AllowAttributeOverrides;
|
||||
import org.apache.fineract.client.models.CreditAllocationData;
|
||||
import org.apache.fineract.client.models.CreditAllocationOrder;
|
||||
import org.apache.fineract.client.models.LoanProductChargeData;
|
||||
@@ -4056,6 +4057,54 @@ public class LoanProductGlobalInitializerStep implements FineractGlobalInitializ
|
||||
TestContext.INSTANCE.set(
|
||||
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY,
|
||||
responseLoanProductsResponseAdvCustomPaymentAllocationProgressiveLoanInterestDailyEmi36030InterestRecalculationDaily);
|
||||
|
||||
// (LP1_WITH_OVERRIDES) - Loan product with all attribute overrides ENABLED
|
||||
final String nameWithOverrides = DefaultLoanProduct.LP1_WITH_OVERRIDES.getName();
|
||||
final PostLoanProductsRequest loanProductsRequestWithOverrides = loanProductsRequestFactory.defaultLoanProductsRequestLP1() //
|
||||
.name(nameWithOverrides) //
|
||||
.interestRatePerPeriod(1.0) //
|
||||
.maxInterestRatePerPeriod(30.0) //
|
||||
.inArrearsTolerance(10) //
|
||||
.graceOnPrincipalPayment(1) //
|
||||
.graceOnInterestPayment(1) //
|
||||
.graceOnArrearsAgeing(3) //
|
||||
.numberOfRepayments(6) //
|
||||
.allowAttributeOverrides(new AllowAttributeOverrides() //
|
||||
.amortizationType(true) //
|
||||
.interestType(true) //
|
||||
.transactionProcessingStrategyCode(true) //
|
||||
.interestCalculationPeriodType(true) //
|
||||
.inArrearsTolerance(true) //
|
||||
.repaymentEvery(true) //
|
||||
.graceOnPrincipalAndInterestPayment(true) //
|
||||
.graceOnArrearsAgeing(true));
|
||||
final Response<PostLoanProductsResponse> responseWithOverrides = loanProductsApi.createLoanProduct(loanProductsRequestWithOverrides)
|
||||
.execute();
|
||||
TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_WITH_OVERRIDES, responseWithOverrides);
|
||||
|
||||
// (LP1_NO_OVERRIDES) - Loan product with all attribute overrides DISABLED
|
||||
final String nameNoOverrides = DefaultLoanProduct.LP1_NO_OVERRIDES.getName();
|
||||
final PostLoanProductsRequest loanProductsRequestNoOverrides = loanProductsRequestFactory.defaultLoanProductsRequestLP1() //
|
||||
.name(nameNoOverrides) //
|
||||
.interestRatePerPeriod(1.0) //
|
||||
.maxInterestRatePerPeriod(30.0) //
|
||||
.inArrearsTolerance(10) //
|
||||
.graceOnPrincipalPayment(1) //
|
||||
.graceOnInterestPayment(1) //
|
||||
.graceOnArrearsAgeing(3) //
|
||||
.numberOfRepayments(6) //
|
||||
.allowAttributeOverrides(new AllowAttributeOverrides() //
|
||||
.amortizationType(false) //
|
||||
.interestType(false) //
|
||||
.transactionProcessingStrategyCode(false) //
|
||||
.interestCalculationPeriodType(false) //
|
||||
.inArrearsTolerance(false) //
|
||||
.repaymentEvery(false) //
|
||||
.graceOnPrincipalAndInterestPayment(false) //
|
||||
.graceOnArrearsAgeing(false));
|
||||
final Response<PostLoanProductsResponse> responseNoOverrides = loanProductsApi.createLoanProduct(loanProductsRequestNoOverrides)
|
||||
.execute();
|
||||
TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_NO_OVERRIDES, responseNoOverrides);
|
||||
}
|
||||
|
||||
public static AdvancedPaymentData createPaymentAllocation(String transactionType, String futureInstallmentAllocationRule,
|
||||
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.test.stepdef.loan;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import io.cucumber.datatable.DataTable;
|
||||
import io.cucumber.java.en.Then;
|
||||
import io.cucumber.java.en.When;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.PostClientsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansRequest;
|
||||
import org.apache.fineract.client.models.PostLoansResponse;
|
||||
import org.apache.fineract.client.services.LoansApi;
|
||||
import org.apache.fineract.test.data.loanproduct.DefaultLoanProduct;
|
||||
import org.apache.fineract.test.data.loanproduct.LoanProductResolver;
|
||||
import org.apache.fineract.test.factory.LoanRequestFactory;
|
||||
import org.apache.fineract.test.helper.ErrorHelper;
|
||||
import org.apache.fineract.test.stepdef.AbstractStepDef;
|
||||
import org.apache.fineract.test.support.TestContextKey;
|
||||
import retrofit2.Response;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class LoanOverrideFieldsStepDef extends AbstractStepDef {
|
||||
|
||||
private final LoanRequestFactory loanRequestFactory;
|
||||
private final LoanProductResolver loanProductResolver;
|
||||
private final LoansApi loansApi;
|
||||
|
||||
@Then("LoanDetails has {string} field with value: {string}")
|
||||
public void checkLoanDetailsFieldWithValue(final String fieldName, final String expectedValue) throws IOException {
|
||||
final Response<PostLoansResponse> loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
||||
assertNotNull(loanResponse.body());
|
||||
final Long loanId = loanResponse.body().getLoanId();
|
||||
|
||||
final Response<GetLoansLoanIdResponse> loanDetails = loansApi.retrieveLoan(loanId, false, "", "", "").execute();
|
||||
ErrorHelper.checkSuccessfulApiCall(loanDetails);
|
||||
assertNotNull(loanDetails.body());
|
||||
|
||||
verifyFieldValue(loanDetails.body(), fieldName, expectedValue);
|
||||
}
|
||||
|
||||
private void verifyFieldValue(final GetLoansLoanIdResponse loanDetails, final String fieldName, final String expectedValue) {
|
||||
final Integer actualValue = getIntFieldValue(loanDetails, fieldName);
|
||||
final Integer expected = Integer.valueOf(expectedValue);
|
||||
assertThat(actualValue).as("Expected %s to be %d but was %s", fieldName, expected, actualValue).isEqualTo(expected);
|
||||
}
|
||||
|
||||
private Integer getIntFieldValue(final GetLoansLoanIdResponse loanDetails, final String fieldName) {
|
||||
return switch (fieldName) {
|
||||
case "inArrearsTolerance" -> loanDetails.getInArrearsTolerance();
|
||||
case "graceOnPrincipalPayment" -> loanDetails.getGraceOnPrincipalPayment();
|
||||
case "graceOnInterestPayment" -> loanDetails.getGraceOnInterestPayment();
|
||||
case "graceOnArrearsAgeing" -> loanDetails.getGraceOnArrearsAgeing();
|
||||
default -> throw new IllegalArgumentException("Unknown override field: " + fieldName);
|
||||
};
|
||||
}
|
||||
|
||||
@When("Admin creates a new Loan with the following override data:")
|
||||
public void createLoanWithOverrideData(final DataTable dataTable) throws IOException {
|
||||
final Response<PostClientsResponse> clientResponse = testContext().get(TestContextKey.CLIENT_CREATE_RESPONSE);
|
||||
assertNotNull(clientResponse.body());
|
||||
final Long clientId = clientResponse.body().getClientId();
|
||||
|
||||
final Map<String, String> overrideData = dataTable.asMap(String.class, String.class);
|
||||
|
||||
final String loanProductName = overrideData.get("loanProduct");
|
||||
if (loanProductName == null) {
|
||||
throw new IllegalArgumentException("loanProduct is required in override data");
|
||||
}
|
||||
|
||||
final PostLoansRequest loansRequest = loanRequestFactory.defaultLoansRequest(clientId)
|
||||
.productId(loanProductResolver.resolve(DefaultLoanProduct.valueOf(loanProductName))).numberOfRepayments(6)
|
||||
.loanTermFrequency(180).interestRatePerPeriod(new BigDecimal(1));
|
||||
|
||||
overrideData.forEach((fieldName, value) -> {
|
||||
if (!"loanProduct".equals(fieldName)) {
|
||||
applyOverrideField(loansRequest, fieldName, value);
|
||||
}
|
||||
});
|
||||
|
||||
final Response<PostLoansResponse> response = loansApi.calculateLoanScheduleOrSubmitLoanApplication(loansRequest, "").execute();
|
||||
testContext().set(TestContextKey.LOAN_CREATE_RESPONSE, response);
|
||||
ErrorHelper.checkSuccessfulApiCall(response);
|
||||
}
|
||||
|
||||
private void applyOverrideField(final PostLoansRequest request, final String fieldName, final String value) {
|
||||
final boolean isNull = "null".equals(value);
|
||||
|
||||
switch (fieldName) {
|
||||
case "inArrearsTolerance" -> request.inArrearsTolerance(isNull ? null : new BigDecimal(value));
|
||||
case "graceOnInterestPayment" -> request.graceOnInterestPayment(isNull ? null : Integer.valueOf(value));
|
||||
case "graceOnPrincipalPayment" -> request.graceOnPrincipalPayment(isNull ? null : Integer.valueOf(value));
|
||||
case "graceOnArrearsAgeing" -> request.graceOnArrearsAgeing(isNull ? null : Integer.valueOf(value));
|
||||
default -> throw new IllegalArgumentException("Unknown override field: " + fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+2
@@ -275,4 +275,6 @@ public abstract class TestContextKey {
|
||||
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_PROGRESSIVE_ADV_PYMNT_INTEREST_RECALC_360_30_MULTIDISB_OVER_APPLIED_EXPECTED_TRANCHES = "loanProductCreateResponseLP2ProgressiveAdvancedPaymentInterestRecalculationMultidisbursalApprovedOverAppliedAmountExpectedTransches";
|
||||
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE_MIN_INT_3_MAX_INT_20 = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationDailyTillPreCloseMinInt3MaxInt20";
|
||||
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_PROGRESSIVE_ADV_PYMNT_WRITE_OFF_REASON_MAP = "loanProductCreateResponseLP2ProgressiveAdvancedPaymentWriteOffReasonMap";
|
||||
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_WITH_OVERRIDES = "loanProductCreateResponseLP1WithOverrides";
|
||||
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_NO_OVERRIDES = "loanProductCreateResponseLP1NoOverrides";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
@LoanOverrideFields
|
||||
Feature: LoanOverrideFields
|
||||
|
||||
Scenario: Verify that all nullable fields default to product when overrides not allowed and not provided
|
||||
When Admin sets the business date to the actual date
|
||||
When Admin creates a client with random data
|
||||
When Admin creates a new Loan with the following override data:
|
||||
| loanProduct | LP1_NO_OVERRIDES |
|
||||
| inArrearsTolerance | null |
|
||||
| graceOnPrincipalPayment | null |
|
||||
| graceOnInterestPayment | null |
|
||||
| graceOnArrearsAgeing | null |
|
||||
Then LoanDetails has "inArrearsTolerance" field with value: "10"
|
||||
Then LoanDetails has "graceOnPrincipalPayment" field with value: "1"
|
||||
Then LoanDetails has "graceOnInterestPayment" field with value: "1"
|
||||
Then LoanDetails has "graceOnArrearsAgeing" field with value: "3"
|
||||
|
||||
Scenario: Verify that all nullable fields ignore overrides when overrides not allowed
|
||||
When Admin sets the business date to the actual date
|
||||
When Admin creates a client with random data
|
||||
When Admin creates a new Loan with the following override data:
|
||||
| loanProduct | LP1_NO_OVERRIDES |
|
||||
| inArrearsTolerance | 11 |
|
||||
| graceOnPrincipalPayment | 2 |
|
||||
| graceOnInterestPayment | 2 |
|
||||
| graceOnArrearsAgeing | 4 |
|
||||
Then LoanDetails has "inArrearsTolerance" field with value: "10"
|
||||
Then LoanDetails has "graceOnPrincipalPayment" field with value: "1"
|
||||
Then LoanDetails has "graceOnInterestPayment" field with value: "1"
|
||||
Then LoanDetails has "graceOnArrearsAgeing" field with value: "3"
|
||||
|
||||
Scenario: Verify that nullable fields default to product when override is allowed but not provided
|
||||
When Admin sets the business date to the actual date
|
||||
When Admin creates a client with random data
|
||||
When Admin creates a new Loan with the following override data:
|
||||
| loanProduct | LP1_WITH_OVERRIDES |
|
||||
| inArrearsTolerance | null |
|
||||
| graceOnPrincipalPayment | null |
|
||||
| graceOnInterestPayment | null |
|
||||
| graceOnArrearsAgeing | null |
|
||||
Then LoanDetails has "inArrearsTolerance" field with value: "10"
|
||||
Then LoanDetails has "graceOnPrincipalPayment" field with value: "1"
|
||||
Then LoanDetails has "graceOnInterestPayment" field with value: "1"
|
||||
Then LoanDetails has "graceOnArrearsAgeing" field with value: "3"
|
||||
|
||||
Scenario: Verify that nullable fields default to product when override is allowed and provided
|
||||
When Admin sets the business date to the actual date
|
||||
When Admin creates a client with random data
|
||||
When Admin creates a new Loan with the following override data:
|
||||
| loanProduct | LP1_WITH_OVERRIDES |
|
||||
| inArrearsTolerance | 11 |
|
||||
| graceOnPrincipalPayment | 2 |
|
||||
| graceOnInterestPayment | 2 |
|
||||
| graceOnArrearsAgeing | 4 |
|
||||
Then LoanDetails has "inArrearsTolerance" field with value: "11"
|
||||
Then LoanDetails has "graceOnPrincipalPayment" field with value: "2"
|
||||
Then LoanDetails has "graceOnInterestPayment" field with value: "2"
|
||||
Then LoanDetails has "graceOnArrearsAgeing" field with value: "4"
|
||||
+10
@@ -1216,6 +1216,14 @@ final class LoansApiResourceSwagger {
|
||||
public Boolean chargedOff;
|
||||
@Schema(example = "3")
|
||||
public Integer inArrearsTolerance;
|
||||
@Schema(example = "0")
|
||||
public Integer graceOnPrincipalPayment;
|
||||
@Schema(example = "0")
|
||||
public Integer graceOnInterestPayment;
|
||||
@Schema(example = "0")
|
||||
public Integer graceOnInterestCharged;
|
||||
@Schema(example = "3")
|
||||
public Integer graceOnArrearsAgeing;
|
||||
@Schema(example = "false")
|
||||
public Boolean enableDownPayment;
|
||||
@Schema(example = "0.000000")
|
||||
@@ -1348,6 +1356,8 @@ final class LoansApiResourceSwagger {
|
||||
public Integer graceOnInterestPayment;
|
||||
@Schema(example = "1")
|
||||
public Integer graceOnArrearsAgeing;
|
||||
@Schema(example = "10")
|
||||
public BigDecimal inArrearsTolerance;
|
||||
@Schema(example = "HORIZONTAL")
|
||||
public String loanScheduleProcessingType;
|
||||
@Schema(example = "false")
|
||||
|
||||
+18
-12
@@ -350,27 +350,33 @@ public class LoanScheduleAssembler {
|
||||
}
|
||||
|
||||
// grace details
|
||||
final Integer graceOnPrincipalPayment = allowOverridingGraceOnPrincipalAndInterestPayment
|
||||
? this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnPrincipalPayment", element)
|
||||
: loanProduct.getLoanProductRelatedDetail().getGraceOnPrincipalPayment();
|
||||
Integer graceOnPrincipalPayment = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnPrincipalPayment", element);
|
||||
if (!allowOverridingGraceOnPrincipalAndInterestPayment || graceOnPrincipalPayment == null) {
|
||||
graceOnPrincipalPayment = loanProduct.getLoanProductRelatedDetail().getGraceOnPrincipalPayment();
|
||||
}
|
||||
final Integer recurringMoratoriumOnPrincipalPeriods = this.fromApiJsonHelper
|
||||
.extractIntegerWithLocaleNamed("recurringMoratoriumOnPrincipalPeriods", element);
|
||||
final Integer graceOnInterestPayment = allowOverridingGraceOnPrincipalAndInterestPayment
|
||||
? this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnInterestPayment", element)
|
||||
: loanProduct.getLoanProductRelatedDetail().getGraceOnInterestPayment();
|
||||
Integer graceOnInterestPayment = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnInterestPayment", element);
|
||||
if (!allowOverridingGraceOnPrincipalAndInterestPayment || graceOnInterestPayment == null) {
|
||||
graceOnInterestPayment = loanProduct.getLoanProductRelatedDetail().getGraceOnInterestPayment();
|
||||
}
|
||||
final Integer graceOnInterestCharged = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnInterestCharged", element);
|
||||
final LocalDate interestChargedFromDate = this.fromApiJsonHelper.extractLocalDateNamed("interestChargedFromDate", element);
|
||||
final Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled = this.configurationDomainService
|
||||
.isInterestChargedFromDateSameAsDisbursementDate();
|
||||
|
||||
final Integer graceOnArrearsAgeing = allowOverridingGraceOnArrearsAging
|
||||
? this.fromApiJsonHelper.extractIntegerWithLocaleNamed(LoanProductConstants.GRACE_ON_ARREARS_AGEING_PARAMETER_NAME, element)
|
||||
: loanProduct.getLoanProductRelatedDetail().getGraceOnArrearsAgeing();
|
||||
Integer graceOnArrearsAgeing = this.fromApiJsonHelper
|
||||
.extractIntegerWithLocaleNamed(LoanProductConstants.GRACE_ON_ARREARS_AGEING_PARAMETER_NAME, element);
|
||||
if (!allowOverridingGraceOnArrearsAging || graceOnArrearsAgeing == null) {
|
||||
graceOnArrearsAgeing = loanProduct.getLoanProductRelatedDetail().getGraceOnArrearsAgeing();
|
||||
}
|
||||
|
||||
// other
|
||||
final BigDecimal inArrearsTolerance = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("inArrearsTolerance", element);
|
||||
final Money inArrearsToleranceMoney = allowOverridingArrearsTolerance ? Money.of(currency, inArrearsTolerance)
|
||||
: loanProduct.getLoanProductRelatedDetail().getInArrearsTolerance();
|
||||
BigDecimal inArrearsTolerance = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("inArrearsTolerance", element);
|
||||
if (!allowOverridingArrearsTolerance || inArrearsTolerance == null) {
|
||||
inArrearsTolerance = loanProduct.getLoanProductRelatedDetail().getInArrearsTolerance().getAmount();
|
||||
}
|
||||
final Money inArrearsToleranceMoney = Money.of(currency, inArrearsTolerance);
|
||||
|
||||
final BigDecimal emiAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(LoanApiConstants.fixedEmiAmountParameterName,
|
||||
element);
|
||||
|
||||
+22
-8
@@ -886,7 +886,8 @@ public abstract class BaseLoanIntegrationTest extends IntegrationTest {
|
||||
.repaymentEvery(1)//
|
||||
.repaymentFrequencyType(RepaymentFrequencyType.MONTHS.longValue())//
|
||||
.interestType(interestType)//
|
||||
.amortizationType(amortizationType);
|
||||
.amortizationType(amortizationType)//
|
||||
.graceOnArrearsAgeing(0);
|
||||
}
|
||||
|
||||
private RequestSpecification createRequestSpecification(String authKey) {
|
||||
@@ -1352,13 +1353,26 @@ public abstract class BaseLoanIntegrationTest extends IntegrationTest {
|
||||
protected PostLoansRequest applyLoanRequest(Long clientId, Long loanProductId, String loanDisbursementDate, Double amount,
|
||||
int numberOfRepayments, Consumer<PostLoansRequest> customizer) {
|
||||
|
||||
PostLoansRequest postLoansRequest = new PostLoansRequest().clientId(clientId).productId(loanProductId)
|
||||
.expectedDisbursementDate(loanDisbursementDate).dateFormat(DATETIME_PATTERN)
|
||||
.transactionProcessingStrategyCode(DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY)
|
||||
.locale("en").submittedOnDate(loanDisbursementDate).amortizationType(1).interestRatePerPeriod(BigDecimal.ZERO)
|
||||
.interestCalculationPeriodType(1).interestType(0).repaymentEvery(30).repaymentFrequencyType(0)
|
||||
.numberOfRepayments(numberOfRepayments).loanTermFrequency(numberOfRepayments * 30).loanTermFrequencyType(0)
|
||||
.maxOutstandingLoanBalance(BigDecimal.valueOf(amount)).principal(BigDecimal.valueOf(amount)).loanType("individual");
|
||||
PostLoansRequest postLoansRequest = new PostLoansRequest().clientId(clientId) //
|
||||
.productId(loanProductId) //
|
||||
.expectedDisbursementDate(loanDisbursementDate) //
|
||||
.dateFormat(DATETIME_PATTERN) //
|
||||
.transactionProcessingStrategyCode(DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY) //
|
||||
.locale("en") //
|
||||
.submittedOnDate(loanDisbursementDate) //
|
||||
.amortizationType(1) //
|
||||
.interestRatePerPeriod(BigDecimal.ZERO) //
|
||||
.interestCalculationPeriodType(1) //
|
||||
.interestType(0) //
|
||||
.repaymentEvery(30) //
|
||||
.repaymentFrequencyType(0) //
|
||||
.numberOfRepayments(numberOfRepayments) //
|
||||
.loanTermFrequency(numberOfRepayments * 30) //
|
||||
.loanTermFrequencyType(0) //
|
||||
.maxOutstandingLoanBalance(BigDecimal.valueOf(amount)) //
|
||||
.principal(BigDecimal.valueOf(amount)) //
|
||||
.loanType("individual") //
|
||||
.graceOnArrearsAgeing(0);
|
||||
if (customizer != null) {
|
||||
customizer.accept(postLoansRequest);
|
||||
}
|
||||
|
||||
+5
-5
@@ -285,15 +285,15 @@ public class DelinquencyActionIntegrationTests extends BaseLoanIntegrationTest {
|
||||
verifyLoanDelinquencyData(loanId, 6, new InstallmentDelinquencyData(4, 10, BigDecimal.valueOf(250.0)));
|
||||
|
||||
// Create Delinquency Pause for the Loan in the past
|
||||
PostLoansDelinquencyActionResponse response = loanTransactionHelper.createLoanDelinquencyAction(loanId, PAUSE,
|
||||
"27 January 2023", "15 February 2023");
|
||||
loanTransactionHelper.createLoanDelinquencyAction(loanId, PAUSE, "27 January 2023", "15 February 2023");
|
||||
|
||||
List<GetDelinquencyActionsResponse> loanDelinquencyActions = loanTransactionHelper.getLoanDelinquencyActions(loanId);
|
||||
Assertions.assertNotNull(loanDelinquencyActions);
|
||||
Assertions.assertEquals(1, loanDelinquencyActions.size());
|
||||
Assertions.assertEquals("PAUSE", loanDelinquencyActions.get(0).getAction());
|
||||
Assertions.assertEquals(LocalDate.parse("27 January 2023", dateTimeFormatter), loanDelinquencyActions.get(0).getStartDate());
|
||||
Assertions.assertEquals(LocalDate.parse("15 February 2023", dateTimeFormatter), loanDelinquencyActions.get(0).getEndDate());
|
||||
Assertions.assertEquals("PAUSE", loanDelinquencyActions.getFirst().getAction());
|
||||
Assertions.assertEquals(LocalDate.parse("27 January 2023", dateTimeFormatter),
|
||||
loanDelinquencyActions.getFirst().getStartDate());
|
||||
Assertions.assertEquals(LocalDate.parse("15 February 2023", dateTimeFormatter), loanDelinquencyActions.getFirst().getEndDate());
|
||||
|
||||
// Loan delinquency data calculation after backdated pause
|
||||
verifyLoanDelinquencyData(loanId, 3, new InstallmentDelinquencyData(1, 3, BigDecimal.valueOf(250.0)));
|
||||
|
||||
+2
-2
@@ -137,8 +137,8 @@ public class LoanProductTestBuilder {
|
||||
private String minimumGuaranteeFromOwnFunds = null;
|
||||
private String minimumGuaranteeFromGuarantor = null;
|
||||
private String isArrearsBasedOnOriginalSchedule = null;
|
||||
private String graceOnPrincipalPayment = "1";
|
||||
private String graceOnInterestPayment = "1";
|
||||
private String graceOnPrincipalPayment = null;
|
||||
private String graceOnInterestPayment = null;
|
||||
private JsonObject allowAttributeOverrides = null;
|
||||
private Boolean allowPartialPeriodInterestCalcualtion = false;
|
||||
|
||||
|
||||
+2
-2
@@ -1368,8 +1368,8 @@ public class InitiateExternalAssetOwnerTransferTest extends BaseLoanIntegrationT
|
||||
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("4").withRepaymentEveryAfter("1")
|
||||
.withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("2").withAmortizationTypeAsEqualInstallments()
|
||||
.withInterestTypeAsDecliningBalance().withInterestCalculationPeriodTypeSameAsRepaymentPeriod()
|
||||
.withExpectedDisbursementDate(date).withSubmittedOnDate(date).withCollaterals(collaterals)
|
||||
.build(clientID, loanProductID, null);
|
||||
.withExpectedDisbursementDate(date).withSubmittedOnDate(date).withCollaterals(collaterals).withInArrearsTolerance("0")
|
||||
.withPrincipalGrace("0").withInterestGrace("0").build(clientID, loanProductID, null);
|
||||
return LOAN_TRANSACTION_HELPER.getLoanId(loanApplicationJSON);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user