blob: 93da039e9ca06d4407ffeb41efa2bf8b5dd92e56 [file] [log] [blame]
/**
* 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 static org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder.DEFAULT_STRATEGY;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.http.ContentType;
import io.restassured.path.json.JsonPath;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.fineract.client.models.AdvancedPaymentData;
import org.apache.fineract.client.models.GetLoanRescheduleRequestResponse;
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
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.PostLoansLoanIdRequest;
import org.apache.fineract.client.models.PostLoansRequest;
import org.apache.fineract.client.models.PostLoansResponse;
import org.apache.fineract.client.models.PostUpdateRescheduleLoansRequest;
import org.apache.fineract.client.util.CallFailedRuntimeException;
import org.apache.fineract.integrationtests.common.ClientHelper;
import org.apache.fineract.integrationtests.common.CollateralManagementHelper;
import org.apache.fineract.integrationtests.common.LoanRescheduleRequestHelper;
import org.apache.fineract.integrationtests.common.Utils;
import org.apache.fineract.integrationtests.common.accounting.Account;
import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
import org.apache.fineract.integrationtests.common.loans.LoanRescheduleRequestTestBuilder;
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Test the creation, approval and rejection of a loan reschedule request
**/
@SuppressWarnings({ "rawtypes" })
public class LoanRescheduleRequestTest extends BaseLoanIntegrationTest {
private static final Logger LOG = LoggerFactory.getLogger(LoanRescheduleRequestTest.class);
private ResponseSpecification responseSpec;
private ResponseSpecification generalResponseSpec;
private RequestSpecification requestSpec;
private LoanTransactionHelper loanTransactionHelper;
private LoanRescheduleRequestHelper loanRescheduleRequestHelper;
private Integer clientId;
private Integer loanProductId;
private Integer loanId;
private Integer loanRescheduleRequestId;
private final String loanPrincipalAmount = "100000.00";
private final String numberOfRepayments = "12";
private final String interestRatePerPeriod = "18";
private final String dateString = "04 September 2014";
@BeforeEach
public void initialize() {
Utils.initializeRESTAssured();
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
this.loanRescheduleRequestHelper = new LoanRescheduleRequestHelper(this.requestSpec, this.responseSpec);
this.generalResponseSpec = new ResponseSpecBuilder().build();
// create all required entities
this.createRequiredEntities();
}
/**
* Creates the client, loan product, and loan entities
**/
private void createRequiredEntities() {
this.createClientEntity();
this.createLoanProductEntity();
this.createLoanEntity();
}
/**
* create a new client
**/
private void createClientEntity() {
this.clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec);
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, this.clientId);
}
/**
* create a new loan product
**/
private void createLoanProductEntity() {
LOG.info("---------------------------------CREATING LOAN PRODUCT------------------------------------------");
final String loanProductJSON = new LoanProductTestBuilder().withPrincipal(loanPrincipalAmount)
.withNumberOfRepayments(numberOfRepayments).withinterestRatePerPeriod(interestRatePerPeriod)
.withInterestRateFrequencyTypeAsYear().build(null);
this.loanProductId = this.loanTransactionHelper.getLoanProductId(loanProductJSON);
LOG.info("Successfully created loan product (ID:{}) ", this.loanProductId);
}
/**
* submit a new loan application, approve and disburse the loan
**/
private void createLoanEntity() {
LOG.info("---------------------------------NEW LOAN APPLICATION------------------------------------------");
List<HashMap> collaterals = new ArrayList<>();
final Integer collateralId = CollateralManagementHelper.createCollateralProduct(this.requestSpec, this.responseSpec);
Assertions.assertNotNull(collateralId);
final Integer clientCollateralId = CollateralManagementHelper.createClientCollateral(this.requestSpec, this.responseSpec,
this.clientId.toString(), collateralId);
Assertions.assertNotNull(clientCollateralId);
addCollaterals(collaterals, clientCollateralId, BigDecimal.valueOf(1));
final String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal(loanPrincipalAmount)
.withLoanTermFrequency(numberOfRepayments).withLoanTermFrequencyAsMonths().withNumberOfRepayments(numberOfRepayments)
.withRepaymentEveryAfter("1").withRepaymentFrequencyTypeAsMonths().withAmortizationTypeAsEqualInstallments()
.withInterestCalculationPeriodTypeAsDays().withInterestRatePerPeriod(interestRatePerPeriod).withLoanTermFrequencyAsMonths()
.withSubmittedOnDate(dateString).withExpectedDisbursementDate(dateString).withPrincipalGrace("2").withInterestGrace("2")
.withCollaterals(collaterals).build(this.clientId.toString(), this.loanProductId.toString(), null);
this.loanId = this.loanTransactionHelper.getLoanId(loanApplicationJSON);
LOG.info("Sucessfully created loan (ID: {} )", this.loanId);
this.approveLoanApplication();
this.disburseLoan();
}
private void addCollaterals(List<HashMap> collaterals, Integer collateralId, BigDecimal quantity) {
collaterals.add(collaterals(collateralId, quantity));
}
private HashMap<String, String> collaterals(Integer collateralId, BigDecimal quantity) {
HashMap<String, String> collateral = new HashMap<String, String>(2);
collateral.put("clientCollateralId", collateralId.toString());
collateral.put("quantity", quantity.toString());
return collateral;
}
/**
* approve the loan application
**/
private void approveLoanApplication() {
if (this.loanId != null) {
this.loanTransactionHelper.approveLoan(this.dateString, this.loanId);
LOG.info("Successfully approved loan (ID: {} )", this.loanId);
}
}
/**
* disburse the newly created loan
**/
private void disburseLoan() {
if (this.loanId != null) {
String loanDetails = this.loanTransactionHelper.getLoanDetails(this.requestSpec, this.responseSpec, this.loanId);
this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount(this.dateString, this.loanId,
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
LOG.info("Successfully disbursed loan (ID: {} )", this.loanId);
}
}
/**
* create new loan reschedule request
**/
private void createLoanRescheduleRequest() {
LOG.info("---------------------------------CREATING LOAN RESCHEDULE REQUEST------------------------------------------");
final String requestJSON = new LoanRescheduleRequestTestBuilder().build(this.loanId.toString());
this.loanRescheduleRequestId = this.loanRescheduleRequestHelper.createLoanRescheduleRequest(requestJSON);
this.loanRescheduleRequestHelper.verifyCreationOfLoanRescheduleRequest(this.loanRescheduleRequestId);
LOG.info("Successfully created loan reschedule request (ID: {} )", this.loanRescheduleRequestId);
}
@Test
public void testCreateLoanRescheduleRequest() {
this.createLoanRescheduleRequest();
}
@Test
public void testRejectLoanRescheduleRequest() {
this.createLoanRescheduleRequest();
LOG.info("-----------------------------REJECTING LOAN RESCHEDULE REQUEST--------------------------");
final String requestJSON = new LoanRescheduleRequestTestBuilder().getRejectLoanRescheduleRequestJSON();
this.loanRescheduleRequestHelper.rejectLoanRescheduleRequest(this.loanRescheduleRequestId, requestJSON);
final HashMap response = (HashMap) this.loanRescheduleRequestHelper.getLoanRescheduleRequest(loanRescheduleRequestId, "statusEnum");
assertTrue((Boolean) response.get("rejected"));
LOG.info("Successfully rejected loan reschedule request (ID: {} )", this.loanRescheduleRequestId);
}
@Test
public void testApproveLoanRescheduleRequest() {
this.createLoanRescheduleRequest();
LOG.info("-----------------------------APPROVING LOAN RESCHEDULE REQUEST--------------------------");
final String requestJSON = new LoanRescheduleRequestTestBuilder().getApproveLoanRescheduleRequestJSON();
this.loanRescheduleRequestHelper.approveLoanRescheduleRequest(this.loanRescheduleRequestId, requestJSON);
final HashMap response = (HashMap) this.loanRescheduleRequestHelper.getLoanRescheduleRequest(loanRescheduleRequestId, "statusEnum");
assertTrue((Boolean) response.get("approved"));
final Integer numberOfRepayments = (Integer) this.loanTransactionHelper.getLoanDetail(requestSpec, generalResponseSpec, loanId,
"numberOfRepayments");
final HashMap loanSummary = this.loanTransactionHelper.getLoanSummary(requestSpec, generalResponseSpec, loanId);
final Float totalExpectedRepayment = (Float) loanSummary.get("totalExpectedRepayment");
assertEquals(12, numberOfRepayments, "NUMBER OF REPAYMENTS is NOK");
assertEquals(118000, totalExpectedRepayment, "TOTAL EXPECTED REPAYMENT is NOK");
LOG.info("Successfully approved loan reschedule request (ID: {})", this.loanRescheduleRequestId);
}
@Test
public void testInterestRateChangeForProgressiveLoan() {
PostClientsResponse client = clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
final Account assetAccount = accountHelper.createAssetAccount();
final Account incomeAccount = accountHelper.createIncomeAccount();
final Account expenseAccount = accountHelper.createExpenseAccount();
final Account overpaymentAccount = accountHelper.createLiabilityAccount();
Integer commonLoanProductId = createLoanProduct("500", "15", "4", true, "25", true, LoanScheduleType.PROGRESSIVE,
LoanScheduleProcessingType.HORIZONTAL, assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
AtomicReference<PostCreateRescheduleLoansResponse> rescheduleResponse = new AtomicReference<>();
AtomicReference<PostLoansResponse> loanResponse = new AtomicReference<>();
// Do not allow interest rate change on not active loan
// Do not allow interest rate change twice on the same day
runAt("15 February 2023", () -> {
loanResponse.set(applyForLoanApplication(client.getClientId(), commonLoanProductId, BigDecimal.valueOf(500.0), 45, 15, 3,
BigDecimal.TEN, "01 January 2023", "01 January 2023"));
loanTransactionHelper.approveLoan(loanResponse.get().getLoanId(),
new PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(500)).dateFormat(DATETIME_PATTERN)
.approvedOnDate("01 January 2023").locale("en"));
CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class,
() -> loanRescheduleRequestHelper
.createLoanRescheduleRequest(new PostCreateRescheduleLoansRequest().loanId(loanResponse.get().getLoanId())
.dateFormat(DATETIME_PATTERN).locale("en").submittedOnDate("15 February 2023")
.newInterestRate(BigDecimal.ONE).rescheduleReasonId(1L).rescheduleFromDate("16 February 2023")));
assertEquals(400, exception.getResponse().code());
assertTrue(exception.getMessage().contains("loan.is.not.active"));
loanTransactionHelper.disburseLoan(loanResponse.get().getLoanId(),
new PostLoansLoanIdRequest().actualDisbursementDate("15 February 2023").dateFormat(DATETIME_PATTERN)
.transactionAmount(BigDecimal.valueOf(500.00)).locale("en"));
rescheduleResponse.set(loanRescheduleRequestHelper.createLoanRescheduleRequest(new PostCreateRescheduleLoansRequest()
.loanId(loanResponse.get().getLoanId()).dateFormat(DATETIME_PATTERN).locale("en").submittedOnDate("15 February 2023")
.newInterestRate(BigDecimal.ONE).rescheduleReasonId(1L).rescheduleFromDate("16 February 2023")));
exception = assertThrows(CallFailedRuntimeException.class,
() -> loanRescheduleRequestHelper
.createLoanRescheduleRequest(new PostCreateRescheduleLoansRequest().loanId(loanResponse.get().getLoanId())
.dateFormat(DATETIME_PATTERN).locale("en").submittedOnDate("15 February 2023")
.newInterestRate(BigDecimal.ONE).rescheduleReasonId(1L).rescheduleFromDate("16 February 2023")));
assertEquals(403, exception.getResponse().code());
assertTrue(exception.getMessage().contains("loan.reschedule.interest.rate.change.already.exists"));
});
// Do not allow approve an interest rate change if the reschedule from date is not in the future
// Do not allow create interest rate change if a previous interest rate change got already approved for that
// date
runAt("16 February 2023", () -> {
PostCreateRescheduleLoansResponse rescheduleLoansResponse = loanRescheduleRequestHelper
.createLoanRescheduleRequest(new PostCreateRescheduleLoansRequest().loanId(loanResponse.get().getLoanId())
.dateFormat(DATETIME_PATTERN).locale("en").submittedOnDate("17 February 2023").newInterestRate(BigDecimal.ONE)
.rescheduleReasonId(1L).rescheduleFromDate("17 February 2023"));
loanRescheduleRequestHelper.approveLoanRescheduleRequest(rescheduleLoansResponse.getResourceId(),
new PostUpdateRescheduleLoansRequest().approvedOnDate("17 February 2024").locale("en").dateFormat(DATETIME_PATTERN));
CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class,
() -> loanRescheduleRequestHelper
.createLoanRescheduleRequest(new PostCreateRescheduleLoansRequest().loanId(rescheduleLoansResponse.getLoanId())
.dateFormat(DATETIME_PATTERN).locale("en").submittedOnDate("17 February 2023")
.newInterestRate(BigDecimal.ONE).rescheduleReasonId(1L).rescheduleFromDate("17 February 2023")));
assertEquals(403, exception.getResponse().code());
assertTrue(exception.getMessage().contains("loan.reschedule.interest.rate.change.already.exists"));
});
// Allow new interest rate change if the previous got rejected
runAt("17 February 2023", () -> {
PostCreateRescheduleLoansResponse rescheduleLoansResponse = loanRescheduleRequestHelper
.createLoanRescheduleRequest(new PostCreateRescheduleLoansRequest().loanId(loanResponse.get().getLoanId())
.dateFormat(DATETIME_PATTERN).locale("en").submittedOnDate("18 February 2023").newInterestRate(BigDecimal.ONE)
.rescheduleReasonId(1L).rescheduleFromDate("18 February 2023"));
loanRescheduleRequestHelper.rejectLoanRescheduleRequest(rescheduleLoansResponse.getResourceId(),
new PostUpdateRescheduleLoansRequest().rejectedOnDate("18 February 2024").locale("en").dateFormat(DATETIME_PATTERN));
loanRescheduleRequestHelper.createLoanRescheduleRequest(new PostCreateRescheduleLoansRequest()
.loanId(loanResponse.get().getLoanId()).dateFormat(DATETIME_PATTERN).locale("en").submittedOnDate("18 February 2023")
.newInterestRate(BigDecimal.ONE).rescheduleReasonId(1L).rescheduleFromDate("18 February 2023"));
});
}
/**
* create new loan reschedule request
**/
private void createLoanRescheduleChangeEMIRequest() {
LOG.info("---------------------------------CREATING LOAN RESCHEDULE REQUEST CHANGE EMI------------------------------------------");
final String requestJSON = new LoanRescheduleRequestTestBuilder().updateGraceOnPrincipal(null).updateGraceOnInterest(null)
.updateExtraTerms(null).updateEMI("5000").updateEmiChangeEndDate("4 February 2015")
.updateRescheduleFromDate("04 January 2015").updateRecalculateInterest(true).build(this.loanId.toString());
this.loanRescheduleRequestId = this.loanRescheduleRequestHelper.createLoanRescheduleRequest(requestJSON);
this.loanRescheduleRequestHelper.verifyCreationOfLoanRescheduleRequest(this.loanRescheduleRequestId);
LOG.info("Successfully created loan reschedule request (ID: {} )", this.loanRescheduleRequestId);
}
@Test
public void testCreateLoanRescheduleChangeEMIRequest() {
this.createLoanRescheduleChangeEMIRequest();
}
@Test
public void givenProgressiveLoanWithPaidInstallmentWhenInterestRateChangedThenDueAmountUpdated() {
PostClientsResponse client = clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
Integer commonLoanProductId = createProgressiveLoanProduct();
AtomicReference<PostLoansResponse> loanResponse = new AtomicReference<>();
runAt("2 February 2024", () -> {
loanResponse
.set(applyForLoanWithRecalculation(client.getClientId(), commonLoanProductId, "01 January 2024", "01 January 2024"));
approveAndDisburseLoan(loanResponse.get().getLoanId(), "01 January 2024", BigDecimal.valueOf(100));
makeRepayments(loanResponse.get().getLoanId().intValue());
GetLoansLoanIdResponse savedLoanResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec,
loanResponse.get().getLoanId().intValue());
PostCreateRescheduleLoansResponse rescheduleLoansResponse = rescheduleLoanWithNewInterestRate(loanResponse.get().getLoanId(),
"2 February 2024", BigDecimal.ONE, "3 February 2024");
approveLoanReschedule(rescheduleLoansResponse.getResourceId(), "2 February 2024");
GetLoansLoanIdResponse actualLoanResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec,
loanResponse.get().getLoanId().intValue());
verifyRepaymentSchedule(savedLoanResponse, actualLoanResponse, 7, 3);
});
}
@Test
public void testLoanTermVariationDeserializesProperly() {
PostClientsResponse client = clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
Long commonLoanProductId = createLoanProductPeriodicWithInterest();
AtomicReference<Long> loanIdRef = new AtomicReference<>();
runAt("01 March 2024", () -> {
Long loanId = applyForLoanApplicationWithInterest(client.getClientId(), commonLoanProductId, BigDecimal.valueOf(4000),
"1 March 2023", "1 March 2024");
loanIdRef.set(loanId);
loanTransactionHelper.approveLoan("1 March 2024", loanId.intValue());
loanTransactionHelper.disburseLoan("1 March 2024", loanId.intValue(), "400", null);
PostCreateRescheduleLoansResponse rescheduleLoansResponse = loanRescheduleRequestHelper
.createLoanRescheduleRequest(new PostCreateRescheduleLoansRequest().loanId(loanIdRef.get()).dateFormat(DATETIME_PATTERN)
.locale("en").submittedOnDate("1 March 2024").newInterestRate(BigDecimal.ONE).rescheduleReasonId(1L)
.rescheduleFromDate("1 April 2024"));
GetLoanRescheduleRequestResponse getLoanRescheduleRequestResponse = Assertions.assertDoesNotThrow(
() -> loanRescheduleRequestHelper.readLoanRescheduleRequest(rescheduleLoansResponse.getResourceId(), null));
Assertions.assertNotNull(getLoanRescheduleRequestResponse);
});
}
private Integer createProgressiveLoanProduct() {
AdvancedPaymentData defaultAllocation = createDefaultPaymentAllocation("NEXT_INSTALLMENT");
final String loanProductJSON = new LoanProductTestBuilder().withNumberOfRepayments(numberOfRepayments)
.withinterestRatePerPeriod("7").withMaxTrancheCount("10").withMinPrincipal("1").withPrincipal("100")
.withInterestRateFrequencyTypeAsYear()
.withRepaymentStrategy(AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY)
.withInterestTypeAsDecliningBalance().addAdvancedPaymentAllocation(defaultAllocation)
.withInterestRecalculationDetails("0", "4", "1").withRecalculationRestFrequencyType("2")
.withInterestCalculationPeriodTypeAsDays().withMultiDisburse().withDisallowExpectedDisbursements()
.withLoanScheduleType(LoanScheduleType.PROGRESSIVE).withLoanScheduleProcessingType(LoanScheduleProcessingType.HORIZONTAL)
.build(null);
return loanTransactionHelper.getLoanProductId(loanProductJSON);
}
private PostLoansResponse applyForLoanWithRecalculation(Long clientId, Integer loanProductId, String expectedDisbursementDate,
String submittedOnDate) {
return loanTransactionHelper.applyLoan(new PostLoansRequest().clientId(clientId).productId(loanProductId.longValue())
.expectedDisbursementDate(expectedDisbursementDate).dateFormat(DATETIME_PATTERN)
.transactionProcessingStrategyCode(AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY)
.locale("en").submittedOnDate(submittedOnDate).amortizationType(1).interestRatePerPeriod(BigDecimal.valueOf(7))
.interestCalculationPeriodType(0).interestType(0).repaymentFrequencyType(2).repaymentEvery(1).numberOfRepayments(6)
.loanTermFrequency(6).loanTermFrequencyType(2).principal(BigDecimal.valueOf(100)).loanType("individual"));
}
private void approveAndDisburseLoan(Long loanId, String date, BigDecimal amount) {
loanTransactionHelper.approveLoan(loanId, createLoanApprovalRequest(date, amount));
loanTransactionHelper.disburseLoan(loanId, createDisbursementRequest(date, amount));
}
private PostLoansLoanIdRequest createLoanApprovalRequest(String date, BigDecimal amount) {
return new PostLoansLoanIdRequest().approvedLoanAmount(amount).dateFormat(DATETIME_PATTERN).approvedOnDate(date).locale("en");
}
private PostLoansLoanIdRequest createDisbursementRequest(String date, BigDecimal amount) {
return new PostLoansLoanIdRequest().actualDisbursementDate(date).dateFormat(DATETIME_PATTERN).transactionAmount(amount)
.locale("en");
}
private void makeRepayments(int loanId) {
loanTransactionHelper.makeRepayment("01 February 2024", 17.01f, loanId);
loanTransactionHelper.makeRepayment("02 February 2024", 17.01f, loanId);
}
private PostCreateRescheduleLoansResponse rescheduleLoanWithNewInterestRate(Long loanId, String submittedOnDate,
BigDecimal newInterestRate, String rescheduleFromDate) {
return loanRescheduleRequestHelper.createLoanRescheduleRequest(new PostCreateRescheduleLoansRequest().loanId(loanId)
.dateFormat(DATETIME_PATTERN).locale("en").submittedOnDate(submittedOnDate).newInterestRate(newInterestRate)
.rescheduleReasonId(1L).rescheduleFromDate(rescheduleFromDate));
}
private void approveLoanReschedule(Long rescheduleId, String approvedOnDate) {
loanRescheduleRequestHelper.approveLoanRescheduleRequest(rescheduleId,
new PostUpdateRescheduleLoansRequest().approvedOnDate(approvedOnDate).locale("en").dateFormat(DATETIME_PATTERN));
}
private PostLoansResponse applyForLoanApplication(final Long clientId, final Integer loanProductId, final BigDecimal principal,
final int loanTermFrequency, final int repaymentAfterEvery, final int numberOfRepayments, final BigDecimal interestRate,
final String expectedDisbursementDate, final String submittedOnDate, String transactionProcessorCode,
String loanScheduleProcessingType) {
LOG.info("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
return loanTransactionHelper.applyLoan(new PostLoansRequest().clientId(clientId).productId(loanProductId.longValue())
.expectedDisbursementDate(expectedDisbursementDate).dateFormat(DATETIME_PATTERN)
.transactionProcessingStrategyCode(transactionProcessorCode).locale("en").submittedOnDate(submittedOnDate)
.amortizationType(1).interestRatePerPeriod(interestRate).interestCalculationPeriodType(1).interestType(0)
.repaymentFrequencyType(0).repaymentEvery(repaymentAfterEvery).repaymentFrequencyType(0)
.numberOfRepayments(numberOfRepayments).loanTermFrequency(loanTermFrequency).loanTermFrequencyType(0).principal(principal)
.loanType("individual").loanScheduleProcessingType(loanScheduleProcessingType)
.maxOutstandingLoanBalance(BigDecimal.valueOf(35000)));
}
private PostLoansResponse applyForLoanApplication(final Long clientId, final Integer loanProductId, final BigDecimal principal,
final int loanTermFrequency, final int repaymentAfterEvery, final int numberOfRepayments, final BigDecimal interestRate,
final String expectedDisbursementDate, final String submittedOnDate) {
return applyForLoanApplication(clientId, loanProductId, principal, loanTermFrequency, repaymentAfterEvery, numberOfRepayments,
interestRate, expectedDisbursementDate, submittedOnDate, LoanScheduleProcessingType.HORIZONTAL);
}
private PostLoansResponse applyForLoanApplication(final Long clientId, final Integer loanProductId, final BigDecimal principal,
final int loanTermFrequency, final int repaymentAfterEvery, final int numberOfRepayments, final BigDecimal interestRate,
final String expectedDisbursementDate, final String submittedOnDate, LoanScheduleProcessingType loanScheduleProcessingType) {
LOG.info("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
return applyForLoanApplication(clientId, loanProductId, principal, loanTermFrequency, repaymentAfterEvery, numberOfRepayments,
interestRate, expectedDisbursementDate, submittedOnDate,
AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY, loanScheduleProcessingType.name());
}
private Integer createLoanProduct(final String principal, final String repaymentAfterEvery, final String numberOfRepayments,
boolean downPaymentEnabled, String downPaymentPercentage, boolean autoPayForDownPayment, LoanScheduleType loanScheduleType,
LoanScheduleProcessingType loanScheduleProcessingType, final Account... accounts) {
AdvancedPaymentData defaultAllocation = createDefaultPaymentAllocation("NEXT_INSTALLMENT");
LOG.info("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
final String loanProductJSON = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal)
.withRepaymentTypeAsDays().withRepaymentAfterEvery(repaymentAfterEvery).withNumberOfRepayments(numberOfRepayments)
.withEnableDownPayment(downPaymentEnabled, downPaymentPercentage, autoPayForDownPayment).withinterestRatePerPeriod("0")
.withInterestRateFrequencyTypeAsMonths()
.withRepaymentStrategy(AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY)
.withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsFlat().withAccountingRulePeriodicAccrual(accounts)
.addAdvancedPaymentAllocation(defaultAllocation).withInterestCalculationPeriodTypeAsRepaymentPeriod(true)
.withInterestTypeAsDecliningBalance().withMultiDisburse().withDisallowExpectedDisbursements(true)
.withLoanScheduleType(loanScheduleType).withLoanScheduleProcessingType(loanScheduleProcessingType).withDaysInMonth("30")
.withDaysInYear("365").withMoratorium("0", "0").build(null);
return loanTransactionHelper.getLoanProductId(loanProductJSON);
}
private Long createLoanProductPeriodicWithInterest() {
String name = Utils.uniqueRandomStringGenerator("LOAN_PRODUCT_", 6);
String shortName = Utils.uniqueRandomStringGenerator("", 4);
Long resourceId = loanTransactionHelper.createLoanProduct(new PostLoanProductsRequest() //
.name(name) //
.shortName(shortName) //
.multiDisburseLoan(true) //
.maxTrancheCount(2) //
.interestType(InterestType.DECLINING_BALANCE) //
.interestCalculationPeriodType(InterestCalculationPeriodType.DAILY) //
.disallowExpectedDisbursements(true) //
.description("Test loan description") //
.currencyCode("USD") //
.digitsAfterDecimal(2) //
.daysInYearType(DaysInYearType.ACTUAL) //
.daysInMonthType(DaysInYearType.ACTUAL) //
.interestRecalculationCompoundingMethod(0) //
.recalculationRestFrequencyType(1) //
.rescheduleStrategyMethod(1) //
.recalculationRestFrequencyInterval(0) //
.isInterestRecalculationEnabled(false) //
.interestRateFrequencyType(2) //
.locale("en_GB") //
.numberOfRepayments(4) //
.repaymentFrequencyType(RepaymentFrequencyType.MONTHS.longValue()) //
.interestRatePerPeriod(2.0) //
.repaymentEvery(1) //
.minPrincipal(100.0) //
.principal(1000.0) //
.maxPrincipal(10000000.0) //
.amortizationType(AmortizationType.EQUAL_INSTALLMENTS) //
.dateFormat(DATETIME_PATTERN) //
.transactionProcessingStrategyCode(DEFAULT_STRATEGY) //
.accountingRule(1)) //
.getResourceId();
return resourceId;
}
private Long applyForLoanApplicationWithInterest(final Long clientId, final Long loanProductId, BigDecimal principal,
String submittedOnDate, String expectedDisburmentDate) {
final PostLoansRequest loanRequest = new PostLoansRequest() //
.loanTermFrequency(4).locale("en_GB").loanTermFrequencyType(2).numberOfRepayments(4).repaymentFrequencyType(2)
.interestRatePerPeriod(BigDecimal.valueOf(2)).repaymentEvery(1).principal(principal).amortizationType(1).interestType(0)
.interestCalculationPeriodType(0).dateFormat("dd MMMM yyyy").transactionProcessingStrategyCode(DEFAULT_STRATEGY)
.loanType("individual").submittedOnDate(submittedOnDate).expectedDisbursementDate(expectedDisburmentDate).clientId(clientId)
.productId(loanProductId);
Long loanId = loanTransactionHelper.applyLoan(loanRequest).getLoanId();
return loanId;
}
}