From d15fc994e37734822215d34bec62e178d731a59e Mon Sep 17 00:00:00 2001 From: Ruchi Dhamankar Date: Mon, 8 May 2023 21:59:36 +0530 Subject: [PATCH] FINERACT-1724-Accrual-reversal-multiple-disbursement --- .../portfolio/loanaccount/domain/Loan.java | 6 +- .../LoanAccrualTransactionReversalTest.java | 285 ++++++++++++++++++ ...nRescheduleOnDecliningBalanceLoanTest.java | 55 +++- .../SchedulerJobsTestResults.java | 30 +- 4 files changed, 370 insertions(+), 6 deletions(-) create mode 100644 integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccrualTransactionReversalTest.java diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java index 3773ff3b5..ecef2f2a4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java @@ -1335,13 +1335,14 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { if (installment.getFeeChargesCharged(getCurrency()).isLessThan(fee) || installment.getInterestCharged(getCurrency()).isLessThan(interest) || installment.getPenaltyChargesCharged(getCurrency()).isLessThan(penality) - || (getAccruedTill().isEqual(loanTransaction.getTransactionDate()) + || (isInterestBearing() && getAccruedTill().isEqual(loanTransaction.getTransactionDate()) && !installment.getDueDate().isEqual(getAccruedTill()))) { interest = interest.minus(loanTransaction.getInterestPortion(getCurrency())); fee = fee.minus(loanTransaction.getFeeChargesPortion(getCurrency())); penality = penality.minus(loanTransaction.getPenaltyChargesPortion(getCurrency())); loanTransaction.reverse(); } + } } installment.updateAccrualPortion(interest, fee, penality); @@ -5339,8 +5340,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { } public boolean isInterestBearing() { - return getLoanRepaymentScheduleDetail().isInterestRecalculationEnabled() - && BigDecimal.ZERO.compareTo(getLoanRepaymentScheduleDetail().getAnnualNominalInterestRate()) < 0; + return BigDecimal.ZERO.compareTo(getLoanRepaymentScheduleDetail().getAnnualNominalInterestRate()) < 0; } public LocalDate getExpectedMaturityDate() { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccrualTransactionReversalTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccrualTransactionReversalTest.java new file mode 100644 index 000000000..e0fabe178 --- /dev/null +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccrualTransactionReversalTest.java @@ -0,0 +1,285 @@ +/** + * 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.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +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.specification.RequestSpecification; +import io.restassured.specification.ResponseSpecification; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.UUID; +import org.apache.fineract.client.models.GetDelinquencyBucketsResponse; +import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; +import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest; +import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse; +import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; +import org.apache.fineract.integrationtests.common.BusinessDateHelper; +import org.apache.fineract.integrationtests.common.ClientHelper; +import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper; +import org.apache.fineract.integrationtests.common.Utils; +import org.apache.fineract.integrationtests.common.accounting.Account; +import org.apache.fineract.integrationtests.common.accounting.AccountHelper; +import org.apache.fineract.integrationtests.common.accounting.PeriodicAccrualAccountingHelper; +import org.apache.fineract.integrationtests.common.charges.ChargesHelper; +import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; +import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; +import org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension; +import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper; +import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@ExtendWith(LoanTestLifecycleExtension.class) +public class LoanAccrualTransactionReversalTest { + + private ResponseSpecification responseSpec; + private RequestSpecification requestSpec; + private LoanTransactionHelper loanTransactionHelper; + private ClientHelper clientHelper; + private DateTimeFormatter dateFormatter = new DateTimeFormatterBuilder().appendPattern("dd MMMM yyyy").toFormatter(); + private PeriodicAccrualAccountingHelper periodicAccrualAccountingHelper; + private AccountHelper accountHelper; + + @BeforeEach + public void setup() { + 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.clientHelper = new ClientHelper(this.requestSpec, this.responseSpec); + this.periodicAccrualAccountingHelper = new PeriodicAccrualAccountingHelper(this.requestSpec, this.responseSpec); + this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec); + } + + @Test + public void testNoAccrualTransactionReversalForMultipleDisbursementWithChargeForLoanAccountWithNoInterestBearingSchedulePeriodicAccrual() { + + // Accounts for periodic accrual + final Account assetAccount = this.accountHelper.createAssetAccount(); + final Account incomeAccount = this.accountHelper.createIncomeAccount(); + final Account expenseAccount = this.accountHelper.createExpenseAccount(); + final Account overpaymentAccount = this.accountHelper.createLiabilityAccount(); + + // Loan ExternalId + String loanExternalIdStr = UUID.randomUUID().toString(); + + // Delinquency Bucket + final Integer delinquencyBucketId = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec); + final GetDelinquencyBucketsResponse delinquencyBucket = DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec, + delinquencyBucketId); + + // Client and Loan account creation + + final Integer clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue(); + final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProductWithMultipleDisbursement( + loanTransactionHelper, delinquencyBucketId, assetAccount, incomeAccount, expenseAccount, overpaymentAccount); + assertNotNull(getLoanProductsProductResponse); + + final Integer loanId = createLoanAccount(clientId, getLoanProductsProductResponse.getId(), loanExternalIdStr); + // 1st disbursement + loanTransactionHelper.disburseLoanWithTransactionAmount("03 September 2022", loanId, "100"); + // 2nd disbursement + loanTransactionHelper.disburseLoanWithTransactionAmount("04 September 2022", loanId, "300"); + + // Add Charge + Integer penalty = ChargesHelper.createCharges(requestSpec, responseSpec, + ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "10", true)); + + LocalDate targetDate = LocalDate.of(2022, 9, 4); + final String penaltyCharge1AddedDate = dateFormatter.format(targetDate); + + Integer penalty1LoanChargeId = this.loanTransactionHelper.addChargesForLoan(loanId, + LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(penalty), penaltyCharge1AddedDate, "10")); + + // Run accrual till charge date + this.periodicAccrualAccountingHelper.runPeriodicAccrualAccounting(penaltyCharge1AddedDate); + + // verify accrual transaction created + checkAccrualTransaction(targetDate, 0.0f, 0.0f, 10.0f, loanId); + + // 3rd disbursement + loanTransactionHelper.disburseLoanWithTransactionAmount("05 September 2022", loanId, "600"); + + // verify accrual transaction exists with same date,amount and is not reversed by regeneration of repayment + // schedule + checkAccrualTransaction(targetDate, 0.0f, 0.0f, 10.0f, loanId); + + } + + @Test + public void testLastAccrualTransactionReversalRecalculationForLoanAccountWithInterestBearingScheduleWithDecliningBalance() { + + try { + // Set business date + LocalDate currentDate = LocalDate.of(2022, 05, 8); + final String accrualRunTillDate = dateFormatter.format(currentDate); + + GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE); + BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, currentDate); + + // Accounts oof periodic accrual + final Account assetAccount = this.accountHelper.createAssetAccount(); + final Account incomeAccount = this.accountHelper.createIncomeAccount(); + final Account expenseAccount = this.accountHelper.createExpenseAccount(); + final Account overpaymentAccount = this.accountHelper.createLiabilityAccount(); + + // Loan ExternalId + String loanExternalIdStr = UUID.randomUUID().toString(); + + // Client and Loan account creation + + final Integer clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId().intValue(); + + // create loan product + final GetLoanProductsProductIdResponse getLoanProductsProductResponse = createLoanProductWithInterestRecalculation(assetAccount, + incomeAccount, expenseAccount, overpaymentAccount); + assertNotNull(getLoanProductsProductResponse); + // create loan account + final Integer loanId = createLoanAccountWithInterestRecalculation(clientId, getLoanProductsProductResponse.getId(), + loanExternalIdStr); + // run accruals till business date + this.periodicAccrualAccountingHelper.runPeriodicAccrualAccounting(accrualRunTillDate); + // check amount for last accrual on business date + checkAccrualTransaction(currentDate, 0.82f, 0.0f, 0.0f, loanId); + // make repayment on due date + final PostLoansLoanIdTransactionsResponse repaymentTransaction = loanTransactionHelper.makeLoanRepayment(loanExternalIdStr, + new PostLoansLoanIdTransactionsRequest().dateFormat("dd MMMM yyyy").transactionDate("5 February 2022").locale("en") + .transactionAmount(106.57)); + // check previous accrual is reversed and new accrual created for same date and different amount. + checkAccrualTransaction(currentDate, 0.71f, 0.0f, 0.0f, loanId); + } finally { + GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE); + } + + } + + private Integer createLoanAccountWithInterestRecalculation(final Integer clientID, final Long loanProductID, final String externalId) { + + final String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("12") + .withLoanTermFrequencyAsMonths().withNumberOfRepayments("12").withRepaymentEveryAfter("1") + .withRepaymentFrequencyTypeAsMonths().withAmortizationTypeAsEqualInstallments().withInterestCalculationPeriodTypeAsDays() + .withInterestRatePerPeriod("12").withInterestTypeAsDecliningBalance().withPrincipalGrace("2").withInterestGrace("2") + .withExpectedDisbursementDate("05 January 2022").withSubmittedOnDate("05 January 2022").withLoanType("individual") + .withExternalId(externalId).build(clientID.toString(), loanProductID.toString(), null); + + final Integer loanId = loanTransactionHelper.getLoanId(loanApplicationJSON); + loanTransactionHelper.approveLoan("05 January 2022", "1000", loanId, null); + loanTransactionHelper.disburseLoanWithNetDisbursalAmount("05 January 2022", loanId, "1000"); + return loanId; + } + + private GetLoanProductsProductIdResponse createLoanProductWithInterestRecalculation(final Account... accounts) { + + final String interestRecalculationCompoundingMethod = LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE; + final String rescheduleStrategyMethod = LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_NUMBER_OF_INSTALLMENTS; + final String recalculationRestFrequencyType = LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY; + final String recalculationRestFrequencyInterval = "0"; + final String preCloseInterestCalculationStrategy = LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE; + final String recalculationCompoundingFrequencyType = null; + final String recalculationCompoundingFrequencyInterval = null; + final Integer recalculationCompoundingFrequencyOnDayType = null; + final Integer recalculationCompoundingFrequencyDayOfWeekType = null; + final Integer recalculationRestFrequencyOnDayType = null; + final Integer recalculationRestFrequencyDayOfWeekType = null; + + final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("1000").withNumberOfRepayments("12") + .withinterestRatePerPeriod("12").withInterestRateFrequencyTypeAsYear().withInterestTypeAsDecliningBalance() + .withInterestCalculationPeriodTypeAsDays() + .withInterestRecalculationDetails(interestRecalculationCompoundingMethod, rescheduleStrategyMethod, + preCloseInterestCalculationStrategy) + .withInterestRecalculationRestFrequencyDetails(recalculationRestFrequencyType, recalculationRestFrequencyInterval, + recalculationRestFrequencyOnDayType, recalculationRestFrequencyDayOfWeekType) + .withInterestRecalculationCompoundingFrequencyDetails(recalculationCompoundingFrequencyType, + recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyOnDayType, + recalculationCompoundingFrequencyDayOfWeekType) + .withAccountingRulePeriodicAccrual(accounts).build(null); + + final Integer loanProductId = this.loanTransactionHelper.getLoanProductId(loanProductJSON); + return loanTransactionHelper.getLoanProduct(loanProductId); + } + + private GetLoanProductsProductIdResponse createLoanProductWithMultipleDisbursement(final LoanTransactionHelper loanTransactionHelper, + final Integer delinquencyBucketId, final Account... accounts) { + + final HashMap loanProductMap = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth() + .withRepaymentAfterEvery("1").withNumberOfRepayments("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0") + .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsDecliningBalance() + .withAccountingRulePeriodicAccrual(accounts).withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withDaysInMonth("30") + .withDaysInYear("365").withMoratorium("0", "0").withMultiDisburse().withDisallowExpectedDisbursements(true) + .build(null, delinquencyBucketId); + final Integer loanProductId = loanTransactionHelper.getLoanProductId(Utils.convertToJson(loanProductMap)); + return loanTransactionHelper.getLoanProduct(loanProductId); + } + + private Integer createLoanAccount(final Integer clientID, final Long loanProductID, final String externalId) { + + String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("1") + .withLoanTermFrequencyAsMonths().withNumberOfRepayments("1").withRepaymentEveryAfter("1") + .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance() + .withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod() + .withExpectedDisbursementDate("03 September 2022").withSubmittedOnDate("01 September 2022").withLoanType("individual") + .withExternalId(externalId).build(clientID.toString(), loanProductID.toString(), null); + + final Integer loanId = loanTransactionHelper.getLoanId(loanApplicationJSON); + loanTransactionHelper.approveLoan("02 September 2022", "1000", loanId, null); + return loanId; + } + + private void checkAccrualTransaction(final LocalDate transactionDate, final Float interestPortion, final Float feePortion, + final Float penaltyPortion, final Integer loanID) { + + ArrayList transactions = (ArrayList) loanTransactionHelper.getLoanTransactions(this.requestSpec, + this.responseSpec, loanID); + boolean isTransactionFound = false; + for (int i = 0; i < transactions.size(); i++) { + HashMap transactionType = (HashMap) transactions.get(i).get("type"); + boolean isAccrualTransaction = (Boolean) transactionType.get("accrual"); + + if (isAccrualTransaction) { + ArrayList accrualEntryDateAsArray = (ArrayList) transactions.get(i).get("date"); + LocalDate accrualEntryDate = LocalDate.of(accrualEntryDateAsArray.get(0), accrualEntryDateAsArray.get(1), + accrualEntryDateAsArray.get(2)); + + if (transactionDate.isEqual(accrualEntryDate)) { + isTransactionFound = true; + assertEquals(interestPortion, Float.valueOf(String.valueOf(transactions.get(i).get("interestPortion"))), + "Mismatch in transaction amounts"); + assertEquals(feePortion, Float.valueOf(String.valueOf(transactions.get(i).get("feeChargesPortion"))), + "Mismatch in transaction amounts"); + assertEquals(penaltyPortion, Float.valueOf(String.valueOf(transactions.get(i).get("penaltyChargesPortion"))), + "Mismatch in transaction amounts"); + break; + } + } + } + assertTrue(isTransactionFound, "No Accrual entries are posted"); + } + +} diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java index 8618a7fbf..058e1ba08 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanRescheduleOnDecliningBalanceLoanTest.java @@ -97,6 +97,16 @@ public class LoanRescheduleOnDecliningBalanceLoanTest { this.enableConfig(); } + /** + * Creates the client, loan product, and loan entities + **/ + private void createRequiredEntitiesNoInterest() { + this.createClientEntity(); + this.createLoanProductEntityNoInterest(); + this.createLoanEntityNoInterest(); + this.enableConfig(); + } + /** * Creates the client, loan product, and loan entities **/ @@ -131,6 +141,20 @@ public class LoanRescheduleOnDecliningBalanceLoanTest { LOG.info("Successfully created loan product (ID:{}) ", this.loanProductId); } + /** + * create a new loan product + **/ + private void createLoanProductEntityNoInterest() { + LOG.info("-------------------------------- - CREATING LOAN PRODUCT ------------------------------------------"); + + final String loanProductJSON = new LoanProductTestBuilder().withPrincipal(loanPrincipalAmount) + .withNumberOfRepayments(numberOfRepayments).withinterestRatePerPeriod("0").withInterestRateFrequencyTypeAsYear() + .withInterestCalculationPeriodTypeAsDays().build(null); + this.loanProductId = this.loanTransactionHelper.getLoanProductId(loanProductJSON); + LOG.info("Successfully created loan product(ID:{}) ", this.loanProductId); + + } + private void createLoanProductWithInterestRecalculation() { LOG.info( "---------------------------------CREATING LOAN PRODUCT WITH RECALULATION ENABLED ------------------------------------------"); @@ -193,6 +217,35 @@ public class LoanRescheduleOnDecliningBalanceLoanTest { this.disburseLoan(this.dateString); } + /** + * submit a new loan application, approve and disburse the loan + **/ + private void createLoanEntityNoInterest() { + LOG.info("---------------------------------NEW LOAN APPLICATION------------------------------------------"); + + List 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("0").withSubmittedOnDate(dateString) + .withExpectedDisbursementDate(dateString).withCollaterals(collaterals).withPrincipalGrace("2").withInterestGrace("2") + .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.dateString); + this.disburseLoan(this.dateString); + } + private void addCollaterals(List collaterals, Integer collateralId, BigDecimal quantity) { collaterals.add(collaterals(collateralId, quantity)); } @@ -253,7 +306,7 @@ public class LoanRescheduleOnDecliningBalanceLoanTest { @Test public void testCreateLoanRescheduleRequestFailIfLoanIsChargedOff() { // create all required entities - this.createRequiredEntities(); + this.createRequiredEntitiesNoInterest(); this.createLoanRescheduleRequestWhichFailsAsLoanIdChargedOff(); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java index f13d40620..a94cfdc37 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java @@ -623,10 +623,10 @@ public class SchedulerJobsTestResults { Integer overdueFeeChargeId = ChargesHelper.createCharges(requestSpec, responseSpec, ChargesHelper.getLoanOverdueFeeJSON()); Assertions.assertNotNull(overdueFeeChargeId); - final Integer loanProductID = createLoanProduct(overdueFeeChargeId.toString()); + final Integer loanProductID = createLoanProductNoInterest(overdueFeeChargeId.toString()); Assertions.assertNotNull(loanProductID); - final Integer loanID = applyForLoanApplication(clientID.toString(), loanProductID.toString(), null, "10 January 2020"); + final Integer loanID = applyForLoanApplicationNoInterest(clientID.toString(), loanProductID.toString(), null, "10 January 2020"); Assertions.assertNotNull(loanID); HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID); @@ -1183,6 +1183,13 @@ public class SchedulerJobsTestResults { return this.loanTransactionHelper.getLoanProductId(loanProductJSON); } + private Integer createLoanProductNoInterest(final String chargeId) { + final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("15,000.00").withNumberOfRepayments("4") + .withRepaymentAfterEvery("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0") + .withAmortizationTypeAsEqualInstallments().build(chargeId); + return this.loanTransactionHelper.getLoanProductId(loanProductJSON); + } + private Integer createLoanProductWithPeriodicAccrual(final String chargeId) { final Account assetAccount = this.accountHelper.createAssetAccount(); final Account assetFeeAndPenaltyAccount = this.accountHelper.createAssetAccount(); @@ -1228,6 +1235,25 @@ public class SchedulerJobsTestResults { return this.loanTransactionHelper.getLoanId(loanApplicationJSON); } + private Integer applyForLoanApplicationNoInterest(final String clientID, final String loanProductID, final String savingsID, + final String date) { + + List collaterals = new ArrayList<>(); + final Integer collateralId = CollateralManagementHelper.createCollateralProduct(this.requestSpec, this.responseSpec); + Assertions.assertNotNull(collateralId); + final Integer clientCollateralId = CollateralManagementHelper.createClientCollateral(this.requestSpec, this.responseSpec, clientID, + collateralId); + Assertions.assertNotNull(clientCollateralId); + addCollaterals(collaterals, clientCollateralId, BigDecimal.valueOf(1)); + + final String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("15,000.00").withLoanTermFrequency("4") + .withLoanTermFrequencyAsMonths().withNumberOfRepayments("4").withRepaymentEveryAfter("1") + .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("0").withAmortizationTypeAsEqualInstallments() + .withInterestCalculationPeriodTypeSameAsRepaymentPeriod().withExpectedDisbursementDate(date).withSubmittedOnDate(date) + .withCollaterals(collaterals).build(clientID, loanProductID, savingsID); + return this.loanTransactionHelper.getLoanId(loanApplicationJSON); + } + private Integer createFixedDepositProduct(final String validFrom, final String validTo) { FixedDepositProductHelper fixedDepositProductHelper = new FixedDepositProductHelper(requestSpec, responseSpec); final String fixedDepositProductJSON = fixedDepositProductHelper.withPeriodRangeChart().build(validFrom, validTo);