From 983f3d2da0909dddd6810810c2545992825fc1ce Mon Sep 17 00:00:00 2001 From: Adam Saghy Date: Tue, 7 Nov 2023 12:22:01 +0100 Subject: [PATCH] FINERACT-1981: Reschedule loan with new repayment date (Progressive loan schedule) --- .../portfolio/loanaccount/domain/Loan.java | 7 +- ...tractProgressiveLoanScheduleGenerator.java | 59 +++++--- ...heduleRequestWritePlatformServiceImpl.java | 7 +- ...ntAllocationLoanRepaymentScheduleTest.java | 126 +++++++++++++++++- .../common/LoanRescheduleRequestHelper.java | 15 ++- 5 files changed, 191 insertions(+), 23 deletions(-) diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java index ea173c3d4..a8614c9a4 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java @@ -5516,7 +5516,12 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { if (loanSchedule == null) { return; } - updateLoanSchedule(loanSchedule.getInstallments()); + // Either the installments got recalculated or the model + if (loanSchedule.getInstallments() != null) { + updateLoanSchedule(loanSchedule.getInstallments()); + } else { + updateLoanSchedule(loanSchedule.getLoanScheduleModel()); + } this.interestRecalculatedOn = DateUtils.getBusinessLocalDate(); LocalDate lastRepaymentDate = this.getLastRepaymentPeriodDueDate(true); Set charges = this.getActiveCharges(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractProgressiveLoanScheduleGenerator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractProgressiveLoanScheduleGenerator.java index 8912fad65..d46b9aa1b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractProgressiveLoanScheduleGenerator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractProgressiveLoanScheduleGenerator.java @@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.loanschedule.domain; import java.math.BigDecimal; import java.math.MathContext; import java.time.LocalDate; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -117,16 +118,13 @@ public abstract class AbstractProgressiveLoanScheduleGenerator implements LoanSc isFirstRepayment = false; LocalDate scheduledDueDate = adjustedDateDetailsDTO.getChangedScheduleDate(); - // this block is to generate the schedule till the specified - // date(used for calculating preclosure) - boolean isCompletePeriod = true; - if (scheduleParams.getScheduleTillDate() != null && !scheduledDueDate.isBefore(scheduleParams.getScheduleTillDate())) { - if (!scheduledDueDate.isEqual(scheduleParams.getScheduleTillDate())) { - isCompletePeriod = false; - } - scheduledDueDate = scheduleParams.getScheduleTillDate(); - isNextRepaymentAvailable = false; - } + // Loan Schedule Exceptions that need to be applied for Loan Account + LoanTermVariationParams termVariationParams = applyLoanTermVariations(loanApplicationTerms, scheduleParams, scheduledDueDate); + scheduledDueDate = termVariationParams.scheduledDueDate(); + + // Updates total days in term + scheduleParams + .addLoanTermInDays(Math.toIntExact(ChronoUnit.DAYS.between(scheduleParams.getPeriodStartDate(), scheduledDueDate))); ScheduleCurrentPeriodParams currentPeriodParams = new ScheduleCurrentPeriodParams(currency, BigDecimal.ZERO); @@ -134,10 +132,6 @@ public abstract class AbstractProgressiveLoanScheduleGenerator implements LoanSc processDisbursements(loanApplicationTerms, chargesDueAtTimeOfDisbursement, scheduleParams, periods, scheduledDueDate); } - if (currentPeriodParams.isSkipCurrentLoop()) { - continue; - } - // 5 determine principal,interest of repayment period PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod( getPaymentPeriodsInOneYearCalculator(), currentPeriodParams.getInterestCalculationGraceOnRepaymentPeriodFraction(), @@ -178,7 +172,7 @@ public abstract class AbstractProgressiveLoanScheduleGenerator implements LoanSc scheduleParams.getPeriodStartDate(), scheduledDueDate, currentPeriodParams.getPrincipalForThisPeriod(), scheduleParams.getOutstandingBalance(), currentPeriodParams.getInterestForThisPeriod(), currentPeriodParams.getFeeChargesForInstallment(), currentPeriodParams.getPenaltyChargesForInstallment(), - totalInstallmentDue, !isCompletePeriod); + totalInstallmentDue, false); if (principalInterestForThisPeriod.getRescheduleInterestPortion() != null) { installment.setRescheduleInterestPortion(principalInterestForThisPeriod.getRescheduleInterestPortion().getAmount()); } @@ -190,7 +184,7 @@ public abstract class AbstractProgressiveLoanScheduleGenerator implements LoanSc periods.add(installment); - // Updates principal paid map with efective date for reducing + // Updates principal paid map with effective date for reducing // the amount from outstanding balance(interest calculation) updateAmountsWithEffectiveDate(loanApplicationTerms, holidayDetailDTO, scheduleParams, scheduledDueDate, currentPeriodParams, installment); @@ -229,7 +223,9 @@ public abstract class AbstractProgressiveLoanScheduleGenerator implements LoanSc public LoanScheduleDTO rescheduleNextInstallments(MathContext mc, LoanApplicationTerms loanApplicationTerms, Loan loan, HolidayDetailDTO holidayDetailDTO, LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, LocalDate rescheduleFrom) { - return null; + + LoanScheduleModel model = generate(mc, loanApplicationTerms, loan.getActiveCharges(), holidayDetailDTO); + return LoanScheduleDTO.from(null, model); } @Override @@ -626,4 +622,33 @@ public abstract class AbstractProgressiveLoanScheduleGenerator implements LoanSc scheduleParams .reduceOutstandingBalance(currentPeriodParams.getPrincipalForThisPeriod().minus(currentPeriodParams.getReducedBalance())); } + + /** + * @param loanApplicationTerms + * @param scheduleParams + * @param scheduledDueDate + * @return + */ + private LoanTermVariationParams applyLoanTermVariations(final LoanApplicationTerms loanApplicationTerms, + final LoanScheduleParams scheduleParams, final LocalDate scheduledDueDate) { + boolean skipPeriod = false; + boolean recalculateAmounts = false; + LocalDate modifiedScheduledDueDate = scheduledDueDate; + ArrayList variationsData = null; + + // due date changes should be applied only for that dueDate + if (loanApplicationTerms.getLoanTermVariations().hasDueDateVariation(scheduledDueDate)) { + LoanTermVariationsData loanTermVariationsData = loanApplicationTerms.getLoanTermVariations().nextDueDateVariation(); + if (DateUtils.isEqual(modifiedScheduledDueDate, loanTermVariationsData.getTermVariationApplicableFrom())) { + modifiedScheduledDueDate = loanTermVariationsData.getDateValue(); + if (!loanTermVariationsData.isSpecificToInstallment()) { + scheduleParams.setActualRepaymentDate(modifiedScheduledDueDate); + loanApplicationTerms.setNewScheduledDueDateStart(modifiedScheduledDueDate); + } + loanTermVariationsData.setProcessed(true); + } + } + + return new LoanTermVariationParams(skipPeriod, recalculateAmounts, modifiedScheduledDueDate, variationsData); + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java index dba4557f6..3c0d41236 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java @@ -443,7 +443,12 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche final LoanScheduleDTO loanSchedule = loanScheduleGenerator.rescheduleNextInstallments(mathContext, loanApplicationTerms, loan, loanApplicationTerms.getHolidayDetailDTO(), loanRepaymentScheduleTransactionProcessor, rescheduleFromDate); - loan.updateLoanSchedule(loanSchedule.getInstallments()); + // Either the installments got recalculated or the model + if (loanSchedule.getInstallments() != null) { + loan.updateLoanSchedule(loanSchedule.getInstallments()); + } else { + loan.updateLoanSchedule(loanSchedule.getLoanScheduleModel()); + } loan.recalculateAllCharges(); ChangedTransactionDetail changedTransactionDetail = loan.processTransactions(); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java index c177431ec..49002bc38 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AdvancedPaymentAllocationLoanRepaymentScheduleTest.java @@ -28,6 +28,7 @@ import io.restassured.http.ContentType; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; import java.math.BigDecimal; +import java.time.LocalDate; import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -38,15 +39,19 @@ import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.GetLoansLoanIdResponse; import org.apache.fineract.client.models.PaymentAllocationOrder; 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.PostLoansLoanIdRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest; 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.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.LoanRescheduleRequestHelper; import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.accounting.Account; import org.apache.fineract.integrationtests.common.accounting.AccountHelper; @@ -76,6 +81,7 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest { private static AccountHelper accountHelper; private static Integer commonLoanProductId; private static PostClientsResponse client; + private static LoanRescheduleRequestHelper loanRescheduleRequestHelper; @BeforeAll public static void setup() { @@ -88,6 +94,7 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest { businessDateHelper = new BusinessDateHelper(); accountHelper = new AccountHelper(requestSpec, responseSpec); ClientHelper clientHelper = new ClientHelper(requestSpec, responseSpec); + loanRescheduleRequestHelper = new LoanRescheduleRequestHelper(requestSpec, responseSpec); final Account assetAccount = accountHelper.createAssetAccount(); final Account incomeAccount = accountHelper.createIncomeAccount(); @@ -1718,7 +1725,7 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest { // UC101: Multiple disbursement test // ADVANCED_PAYMENT_ALLOCATION_STRATEGY // 1. Disburse the loan - // 3. Pay over the down payment + // 2. Pay over the down payment // 3. Disburse again @Test public void uc101() { @@ -1790,7 +1797,107 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest { validateRepaymentPeriod(loanDetails, 3, 250.0, 50.0, 200.0, 50.0, 0.0); validateRepaymentPeriod(loanDetails, 4, 250.0, 0.0, 250.0, 0.0, 0.0); validateRepaymentPeriod(loanDetails, 5, 250.0, 0.0, 250.0, 0.0, 0.0); - validateRepaymentPeriod(loanDetails, 6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0, 0.0, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0); + validateRepaymentPeriod(loanDetails, 6, LocalDate.of(2023, 2, 22), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0, 0.0, 100.0, 0.0, 0.0, + 0.0, 0.0, 0.0); + assertTrue(loanDetails.getStatus().getActive()); + } finally { + GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE); + } + } + + // UC102: Multiple disbursement & reschedule test + // ADVANCED_PAYMENT_ALLOCATION_STRATEGY + // 1. Disburse the loan (500) + // 2. Reschedule the 2nd period + // 3. Repayment (450) + // 3. Disburse again (250) + // 4. Reschedule the 3rd period to be later than the 2nd disbursement + @Test + public void uc102() { + try { + + GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE); + businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName()) + .date("2023.02.20").dateFormat("yyyy.MM.dd").locale("en")); + + final Account assetAccount = accountHelper.createAssetAccount(); + final Account incomeAccount = accountHelper.createIncomeAccount(); + final Account expenseAccount = accountHelper.createExpenseAccount(); + final Account overpaymentAccount = accountHelper.createLiabilityAccount(); + Integer localLoanProductId = createLoanProduct("500", "15", "4", false, assetAccount, incomeAccount, expenseAccount, + overpaymentAccount); + final PostLoansResponse loanResponse = applyForLoanApplication(client.getClientId(), localLoanProductId, 500L, 45, 15, 3, 0, + "01 January 2023", "01 January 2023"); + + loanTransactionHelper.approveLoan(loanResponse.getLoanId(), + new PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(500)).dateFormat(DATETIME_PATTERN) + .approvedOnDate("01 January 2023").locale("en")); + + loanTransactionHelper.disburseLoan(loanResponse.getLoanId(), + new PostLoansLoanIdRequest().actualDisbursementDate("01 January 2023").dateFormat(DATETIME_PATTERN) + .transactionAmount(BigDecimal.valueOf(500.00)).locale("en")); + + GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId()); + validateLoanSummaryBalances(loanDetails, 500.0, 0.0, 500.0, 0.0, null); + validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2023, 1, 1), 125.0, 0.0, 125.0, 0.0, 0.0); + validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 1, 16), 125.0, 0.0, 125.0, 0.0, 0.0); + validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 1, 31), 125.0, 0.0, 125.0, 0.0, 0.0); + validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 2, 15), 125.0, 0.0, 125.0, 0.0, 0.0); + assertTrue(loanDetails.getStatus().getActive()); + + PostCreateRescheduleLoansResponse rescheduleLoansResponse = loanRescheduleRequestHelper + .createLoanRescheduleRequest(new PostCreateRescheduleLoansRequest().loanId(loanDetails.getId()).locale("en") + .dateFormat(DATETIME_PATTERN).rescheduleReasonId(1L).rescheduleFromDate("16 January 2023") + .adjustedDueDate("31 January 2023").submittedOnDate("16 January 2023")); + + loanRescheduleRequestHelper.approveLoanRescheduleRequest(rescheduleLoansResponse.getResourceId(), + new PostUpdateRescheduleLoansRequest().approvedOnDate("16 January 2023").locale("en").dateFormat(DATETIME_PATTERN)); + + loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId()); + validateLoanSummaryBalances(loanDetails, 500.0, 0.0, 500.0, 0.0, null); + validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2023, 1, 1), 125.0, 0.0, 125.0, 0.0, 0.0); + validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 1, 31), 125.0, 0.0, 125.0, 0.0, 0.0); + validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 2, 15), 125.0, 0.0, 125.0, 0.0, 0.0); + validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 3, 2), 125.0, 0.0, 125.0, 0.0, 0.0); + assertTrue(loanDetails.getStatus().getActive()); + + loanTransactionHelper.makeLoanRepayment(loanResponse.getLoanId(), new PostLoansLoanIdTransactionsRequest() + .dateFormat(DATETIME_PATTERN).transactionDate("16 January 2023").locale("en").transactionAmount(350.0)); + loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId()); + validateLoanSummaryBalances(loanDetails, 150.0, 350.0, 150.0, 350.0, null); + validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2023, 1, 1), 125.0, 125.0, 0.0, 0.0, 125.0); + validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 1, 31), 125.0, 125.0, 0.0, 125.0, 0.0); + validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 2, 15), 125.0, 100.0, 25.0, 100.0, 0.0); + validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 3, 2), 125.0, 0.0, 125.0, 0.0, 0.0); + assertTrue(loanDetails.getStatus().getActive()); + + loanTransactionHelper.disburseLoan(loanResponse.getLoanId(), + new PostLoansLoanIdRequest().actualDisbursementDate("20 February 2023").dateFormat(DATETIME_PATTERN) + .transactionAmount(BigDecimal.valueOf(250.0)).locale("en")); + + loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId()); + validateLoanSummaryBalances(loanDetails, 400.0, 350.0, 400.0, 350.0, null); + validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2023, 1, 1), 125.0, 125.0, 0.0, 0.0, 125.0); + validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 1, 31), 125.0, 125.0, 0.0, 125.0, 0.0); + validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 2, 15), 125.0, 100.0, 25.0, 100.0, 0.0); + validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 2, 20), 62.5, 0.0, 62.5, 0.0, 0.0); + validateRepaymentPeriod(loanDetails, 5, LocalDate.of(2023, 3, 2), 312.5, 0.0, 312.5, 0.0, 0.0); + assertTrue(loanDetails.getStatus().getActive()); + + rescheduleLoansResponse = loanRescheduleRequestHelper.createLoanRescheduleRequest(new PostCreateRescheduleLoansRequest() + .loanId(loanDetails.getId()).locale("en").dateFormat(DATETIME_PATTERN).rescheduleReasonId(1L) + .rescheduleFromDate("15 February 2023").adjustedDueDate("25 February 2023").submittedOnDate("15 February 2023")); + + loanRescheduleRequestHelper.approveLoanRescheduleRequest(rescheduleLoansResponse.getResourceId(), + new PostUpdateRescheduleLoansRequest().approvedOnDate("15 February 2023").locale("en").dateFormat(DATETIME_PATTERN)); + + loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId()); + validateLoanSummaryBalances(loanDetails, 400.0, 350.0, 400.0, 350.0, null); + validateRepaymentPeriod(loanDetails, 1, LocalDate.of(2023, 1, 1), 125.0, 125.0, 0.0, 0.0, 125.0); + validateRepaymentPeriod(loanDetails, 2, LocalDate.of(2023, 1, 31), 125.0, 125.0, 0.0, 125.0, 0.0); + validateRepaymentPeriod(loanDetails, 3, LocalDate.of(2023, 2, 20), 62.5, 0.0, 62.5, 0.0, 0.0); + validateRepaymentPeriod(loanDetails, 4, LocalDate.of(2023, 2, 25), 218.75, 100.0, 118.75, 100.0, 0.0); + validateRepaymentPeriod(loanDetails, 5, LocalDate.of(2023, 3, 12), 218.75, 0.0, 218.75, 0.0, 0.0); assertTrue(loanDetails.getStatus().getActive()); } finally { GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE); @@ -1867,6 +1974,18 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest { return loanTransactionHelper.getLoanProductId(loanProductJSON); } + private static void validateRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, LocalDate dueDate, double principalDue, + double principalPaid, double principalOutstanding, double paidInAdvance, double paidLate) { + GetLoansLoanIdRepaymentPeriod period = loanDetails.getRepaymentSchedule().getPeriods().stream() + .filter(p -> Objects.equals(p.getPeriod(), index)).findFirst().orElseThrow(); + assertEquals(dueDate, period.getDueDate()); + assertEquals(principalDue, period.getPrincipalDue()); + assertEquals(principalPaid, period.getPrincipalPaid()); + assertEquals(principalOutstanding, period.getPrincipalOutstanding()); + assertEquals(paidInAdvance, period.getTotalPaidInAdvanceForPeriod()); + assertEquals(paidLate, period.getTotalPaidLateForPeriod()); + } + private static void validateRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, double principalDue, double principalPaid, double principalOutstanding, double paidInAdvance, double paidLate) { GetLoansLoanIdRepaymentPeriod period = loanDetails.getRepaymentSchedule().getPeriods().stream() @@ -1878,12 +1997,13 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest { assertEquals(paidLate, period.getTotalPaidLateForPeriod()); } - private static void validateRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, double principalDue, + private static void validateRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, LocalDate dueDate, double principalDue, double principalPaid, double principalOutstanding, double feeDue, double feePaid, double feeOutstanding, double penaltyDue, double penaltyPaid, double penaltyOutstanding, double interestDue, double interestPaid, double interestOutstanding, double paidInAdvance, double paidLate) { GetLoansLoanIdRepaymentPeriod period = loanDetails.getRepaymentSchedule().getPeriods().stream() .filter(p -> Objects.equals(p.getPeriod(), index)).findFirst().orElseThrow(); + assertEquals(dueDate, period.getDueDate()); assertEquals(principalDue, period.getPrincipalDue()); assertEquals(principalPaid, period.getPrincipalPaid()); assertEquals(principalOutstanding, period.getPrincipalOutstanding()); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/LoanRescheduleRequestHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/LoanRescheduleRequestHelper.java index 4e3b827f4..901e52dfe 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/LoanRescheduleRequestHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/LoanRescheduleRequestHelper.java @@ -23,8 +23,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; import java.util.HashMap; +import org.apache.fineract.client.models.PostCreateRescheduleLoansRequest; +import org.apache.fineract.client.models.PostCreateRescheduleLoansResponse; +import org.apache.fineract.client.models.PostUpdateRescheduleLoansRequest; +import org.apache.fineract.client.models.PostUpdateRescheduleLoansResponse; +import org.apache.fineract.integrationtests.client.IntegrationTest; -public class LoanRescheduleRequestHelper { +public class LoanRescheduleRequestHelper extends IntegrationTest { private final RequestSpecification requestSpec; private final ResponseSpecification responseSpec; @@ -70,4 +75,12 @@ public class LoanRescheduleRequestHelper { final Integer id = Utils.performServerGet(requestSpec, responseSpec, URL, "id"); assertEquals(requestId, id, "ERROR IN CREATING LOAN RESCHEDULE REQUES"); } + + public PostCreateRescheduleLoansResponse createLoanRescheduleRequest(PostCreateRescheduleLoansRequest request) { + return ok(fineract().rescheduleLoans.createLoanRescheduleRequest(request)); + } + + public PostUpdateRescheduleLoansResponse approveLoanRescheduleRequest(Long scheduleId, PostUpdateRescheduleLoansRequest request) { + return ok(fineract().rescheduleLoans.updateLoanRescheduleRequest(scheduleId, request, "approve")); + } }