FINERACT-2354: Introduce reaging preview API
This commit is contained in:
committed by
Adam Saghy
parent
ed8e9d1376
commit
3efafa778e
+197
-5
@@ -20,19 +20,27 @@ package org.apache.fineract.test.stepdef.loan;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import io.cucumber.datatable.DataTable;
|
||||
import io.cucumber.java.en.Then;
|
||||
import io.cucumber.java.en.When;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.ResponseBody;
|
||||
import org.apache.fineract.client.models.LoanScheduleData;
|
||||
import org.apache.fineract.client.models.LoanSchedulePeriodData;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansResponse;
|
||||
@@ -41,22 +49,23 @@ import org.apache.fineract.test.factory.LoanRequestFactory;
|
||||
import org.apache.fineract.test.helper.ErrorHelper;
|
||||
import org.apache.fineract.test.helper.ErrorMessageHelper;
|
||||
import org.apache.fineract.test.helper.ErrorResponse;
|
||||
import org.apache.fineract.test.helper.Utils;
|
||||
import org.apache.fineract.test.messaging.EventAssertion;
|
||||
import org.apache.fineract.test.messaging.event.loan.LoanReAgeEvent;
|
||||
import org.apache.fineract.test.stepdef.AbstractStepDef;
|
||||
import org.apache.fineract.test.support.TestContextKey;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import retrofit2.Response;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class LoanReAgingStepDef extends AbstractStepDef {
|
||||
|
||||
@Autowired
|
||||
private LoanTransactionsApi loanTransactionsApi;
|
||||
private static final String DATE_FORMAT = "dd MMMM yyyy";
|
||||
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern(DATE_FORMAT);
|
||||
|
||||
@Autowired
|
||||
private EventAssertion eventAssertion;
|
||||
private final LoanTransactionsApi loanTransactionsApi;
|
||||
private final EventAssertion eventAssertion;
|
||||
|
||||
@When("Admin creates a Loan re-aging transaction with the following data:")
|
||||
public void createReAgingTransaction(DataTable table) throws IOException {
|
||||
@@ -302,4 +311,187 @@ public class LoanReAgingStepDef extends AbstractStepDef {
|
||||
assertThat(errorDetails.getHttpStatusCode()).as(ErrorMessageHelper.dateFailureErrorCodeMsg()).isEqualTo(403);
|
||||
assertThat(developerMessage).matches(ErrorMessageHelper.reAgeContractTerminatedLoanFailure());
|
||||
}
|
||||
|
||||
@When("Admin creates a Loan re-aging preview with the following data:")
|
||||
public void createReAgingPreview(DataTable table) throws IOException {
|
||||
Response<PostLoansResponse> loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
||||
long loanId = loanResponse.body().getLoanId();
|
||||
|
||||
List<String> data = table.asLists().get(1);
|
||||
int frequencyNumber = Integer.parseInt(data.get(0));
|
||||
String frequencyType = data.get(1);
|
||||
String startDate = data.get(2);
|
||||
int numberOfInstallments = Integer.parseInt(data.get(3));
|
||||
|
||||
Response<LoanScheduleData> response = loanTransactionsApi
|
||||
.previewReAgeSchedule(loanId, frequencyNumber, frequencyType, startDate, numberOfInstallments, DATE_FORMAT, "en").execute();
|
||||
ErrorHelper.checkSuccessfulApiCall(response);
|
||||
testContext().set(TestContextKey.LOAN_REAGING_PREVIEW_RESPONSE, response);
|
||||
|
||||
log.info(
|
||||
"Re-aging preview created for loan ID: {} with parameters: frequencyNumber={}, frequencyType={}, startDate={}, numberOfInstallments={}",
|
||||
loanId, frequencyNumber, frequencyType, startDate, numberOfInstallments);
|
||||
}
|
||||
|
||||
@When("Admin creates a Loan re-aging preview by Loan external ID with the following data:")
|
||||
public void createReAgingPreviewByLoanExternalId(DataTable table) throws IOException {
|
||||
Response<PostLoansResponse> loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
||||
String loanExternalId = loanResponse.body().getResourceExternalId();
|
||||
|
||||
List<String> data = table.asLists().get(1);
|
||||
int frequencyNumber = Integer.parseInt(data.get(0));
|
||||
String frequencyType = data.get(1);
|
||||
String startDate = data.get(2);
|
||||
int numberOfInstallments = Integer.parseInt(data.get(3));
|
||||
|
||||
Response<LoanScheduleData> response = loanTransactionsApi
|
||||
.previewReAgeSchedule1(loanExternalId, frequencyNumber, frequencyType, startDate, numberOfInstallments, DATE_FORMAT, "en")
|
||||
.execute();
|
||||
ErrorHelper.checkSuccessfulApiCall(response);
|
||||
testContext().set(TestContextKey.LOAN_REAGING_PREVIEW_RESPONSE, response);
|
||||
|
||||
log.info(
|
||||
"Re-aging preview created for loan external ID: {} with parameters: frequencyNumber={}, frequencyType={}, startDate={}, numberOfInstallments={}",
|
||||
loanExternalId, frequencyNumber, frequencyType, startDate, numberOfInstallments);
|
||||
}
|
||||
|
||||
@Then("Loan Repayment schedule preview has {int} periods, with the following data for periods:")
|
||||
public void loanRepaymentSchedulePreviewPeriodsCheck(int linesExpected, DataTable table) {
|
||||
Response<LoanScheduleData> scheduleResponse = testContext().get(TestContextKey.LOAN_REAGING_PREVIEW_RESPONSE);
|
||||
|
||||
List<LoanSchedulePeriodData> repaymentPeriods = scheduleResponse.body().getPeriods();
|
||||
|
||||
Response<PostLoansResponse> loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
||||
String resourceId = String.valueOf(loanResponse.body().getLoanId());
|
||||
|
||||
List<List<String>> data = table.asLists();
|
||||
int nrLines = data.size();
|
||||
int linesActual = (int) repaymentPeriods.stream().filter(r -> r.getPeriod() != null).count();
|
||||
for (int i = 1; i < nrLines; i++) {
|
||||
List<String> expectedValues = data.get(i);
|
||||
String dueDateExpected = expectedValues.get(2);
|
||||
|
||||
List<List<String>> actualValuesList = repaymentPeriods.stream()
|
||||
.filter(r -> dueDateExpected.equals(FORMATTER.format(r.getDueDate())))
|
||||
.map(r -> fetchValuesOfRepaymentSchedule(data.get(0), r)).collect(Collectors.toList());
|
||||
|
||||
boolean containsExpectedValues = actualValuesList.stream().anyMatch(actualValues -> actualValues.equals(expectedValues));
|
||||
assertThat(containsExpectedValues)
|
||||
.as(ErrorMessageHelper.wrongValueInLineInRepaymentSchedule(resourceId, i, actualValuesList, expectedValues)).isTrue();
|
||||
|
||||
assertThat(linesActual).as(ErrorMessageHelper.wrongNumberOfLinesInRepaymentSchedule(resourceId, linesActual, linesExpected))
|
||||
.isEqualTo(linesExpected);
|
||||
}
|
||||
}
|
||||
|
||||
@Then("Loan Repayment schedule preview has the following data in Total row:")
|
||||
public void loanRepaymentScheduleAmountCheck(DataTable table) {
|
||||
List<List<String>> data = table.asLists();
|
||||
List<String> header = data.get(0);
|
||||
List<String> expectedValues = data.get(1);
|
||||
Response<LoanScheduleData> scheduleResponse = testContext().get(TestContextKey.LOAN_REAGING_PREVIEW_RESPONSE);
|
||||
validateRepaymentScheduleTotal(header, scheduleResponse.body(), expectedValues);
|
||||
}
|
||||
|
||||
private List<String> fetchValuesOfRepaymentSchedule(List<String> header, LoanSchedulePeriodData repaymentPeriod) {
|
||||
List<String> actualValues = new ArrayList<>();
|
||||
for (String headerName : header) {
|
||||
switch (headerName) {
|
||||
case "Nr" -> actualValues.add(repaymentPeriod.getPeriod() == null ? null : String.valueOf(repaymentPeriod.getPeriod()));
|
||||
case "Days" ->
|
||||
actualValues.add(repaymentPeriod.getDaysInPeriod() == null ? null : String.valueOf(repaymentPeriod.getDaysInPeriod()));
|
||||
case "Date" ->
|
||||
actualValues.add(repaymentPeriod.getDueDate() == null ? null : FORMATTER.format(repaymentPeriod.getDueDate()));
|
||||
case "Paid date" -> actualValues.add(repaymentPeriod.getObligationsMetOnDate() == null ? null
|
||||
: FORMATTER.format(repaymentPeriod.getObligationsMetOnDate()));
|
||||
case "Balance of loan" -> actualValues.add(repaymentPeriod.getPrincipalLoanBalanceOutstanding() == null ? null
|
||||
: new Utils.DoubleFormatter(repaymentPeriod.getPrincipalLoanBalanceOutstanding().doubleValue()).format());
|
||||
case "Principal due" -> actualValues.add(repaymentPeriod.getPrincipalDue() == null ? null
|
||||
: new Utils.DoubleFormatter(repaymentPeriod.getPrincipalDue().doubleValue()).format());
|
||||
case "Interest" -> actualValues.add(repaymentPeriod.getInterestDue() == null ? null
|
||||
: new Utils.DoubleFormatter(repaymentPeriod.getInterestDue().doubleValue()).format());
|
||||
case "Fees" -> actualValues.add(repaymentPeriod.getFeeChargesDue() == null ? null
|
||||
: new Utils.DoubleFormatter(repaymentPeriod.getFeeChargesDue().doubleValue()).format());
|
||||
case "Penalties" -> actualValues.add(repaymentPeriod.getPenaltyChargesDue() == null ? null
|
||||
: new Utils.DoubleFormatter(repaymentPeriod.getPenaltyChargesDue().doubleValue()).format());
|
||||
case "Due" -> actualValues.add(repaymentPeriod.getTotalDueForPeriod() == null ? null
|
||||
: new Utils.DoubleFormatter(repaymentPeriod.getTotalDueForPeriod().doubleValue()).format());
|
||||
case "Paid" -> actualValues.add(repaymentPeriod.getTotalPaidForPeriod() == null ? null
|
||||
: new Utils.DoubleFormatter(repaymentPeriod.getTotalPaidForPeriod().doubleValue()).format());
|
||||
case "In advance" -> actualValues.add(repaymentPeriod.getTotalPaidInAdvanceForPeriod() == null ? null
|
||||
: new Utils.DoubleFormatter(repaymentPeriod.getTotalPaidInAdvanceForPeriod().doubleValue()).format());
|
||||
case "Late" -> actualValues.add(repaymentPeriod.getTotalPaidLateForPeriod() == null ? null
|
||||
: new Utils.DoubleFormatter(repaymentPeriod.getTotalPaidLateForPeriod().doubleValue()).format());
|
||||
case "Waived" -> actualValues.add(repaymentPeriod.getTotalWaivedForPeriod() == null ? null
|
||||
: new Utils.DoubleFormatter(repaymentPeriod.getTotalWaivedForPeriod().doubleValue()).format());
|
||||
case "Outstanding" -> actualValues.add(repaymentPeriod.getTotalOutstandingForPeriod() == null ? null
|
||||
: new Utils.DoubleFormatter(repaymentPeriod.getTotalOutstandingForPeriod().doubleValue()).format());
|
||||
default -> throw new IllegalStateException(String.format("Header name %s cannot be found", headerName));
|
||||
}
|
||||
}
|
||||
return actualValues;
|
||||
}
|
||||
|
||||
@SuppressFBWarnings("SF_SWITCH_NO_DEFAULT")
|
||||
private List<String> validateRepaymentScheduleTotal(List<String> header, LoanScheduleData repaymentSchedule,
|
||||
List<String> expectedAmounts) {
|
||||
List<String> actualValues = new ArrayList<>();
|
||||
Double paidActual = 0.0;
|
||||
List<LoanSchedulePeriodData> periods = repaymentSchedule.getPeriods();
|
||||
for (LoanSchedulePeriodData period : periods) {
|
||||
if (null != period.getTotalPaidForPeriod()) {
|
||||
paidActual += period.getTotalPaidForPeriod().doubleValue();
|
||||
}
|
||||
}
|
||||
BigDecimal paidActualBd = new BigDecimal(paidActual).setScale(2, RoundingMode.HALF_DOWN);
|
||||
|
||||
for (int i = 0; i < header.size(); i++) {
|
||||
String headerName = header.get(i);
|
||||
String expectedValue = expectedAmounts.get(i);
|
||||
switch (headerName) {
|
||||
case "Principal due" -> assertThat(repaymentSchedule.getTotalPrincipalExpected().doubleValue())//
|
||||
.as(ErrorMessageHelper.wrongAmountInRepaymentSchedulePrincipal(
|
||||
repaymentSchedule.getTotalPrincipalExpected().doubleValue(), Double.valueOf(expectedValue)))//
|
||||
.isEqualTo(Double.valueOf(expectedValue));//
|
||||
case "Interest" -> assertThat(repaymentSchedule.getTotalInterestCharged().doubleValue())//
|
||||
.as(ErrorMessageHelper.wrongAmountInRepaymentScheduleInterest(
|
||||
repaymentSchedule.getTotalInterestCharged().doubleValue(), Double.valueOf(expectedValue)))//
|
||||
.isEqualTo(Double.valueOf(expectedValue));//
|
||||
case "Fees" -> assertThat(repaymentSchedule.getTotalFeeChargesCharged().doubleValue())//
|
||||
.as(ErrorMessageHelper.wrongAmountInRepaymentScheduleFees(
|
||||
repaymentSchedule.getTotalFeeChargesCharged().doubleValue(), Double.valueOf(expectedValue)))//
|
||||
.isEqualTo(Double.valueOf(expectedValue));//
|
||||
case "Penalties" -> assertThat(repaymentSchedule.getTotalPenaltyChargesCharged().doubleValue())//
|
||||
.as(ErrorMessageHelper.wrongAmountInRepaymentSchedulePenalties(
|
||||
repaymentSchedule.getTotalPenaltyChargesCharged().doubleValue(), Double.valueOf(expectedValue)))//
|
||||
.isEqualTo(Double.valueOf(expectedValue));//
|
||||
case "Due" -> assertThat(repaymentSchedule.getTotalRepaymentExpected().doubleValue())//
|
||||
.as(ErrorMessageHelper.wrongAmountInRepaymentScheduleDue(
|
||||
repaymentSchedule.getTotalRepaymentExpected().doubleValue(), Double.valueOf(expectedValue)))//
|
||||
.isEqualTo(Double.valueOf(expectedValue));//
|
||||
case "Paid" -> assertThat(paidActualBd.doubleValue())//
|
||||
.as(ErrorMessageHelper.wrongAmountInRepaymentSchedulePaid(paidActualBd.doubleValue(),
|
||||
Double.valueOf(expectedValue)))//
|
||||
.isEqualTo(Double.valueOf(expectedValue));//
|
||||
case "In advance" -> assertThat(repaymentSchedule.getTotalPaidInAdvance().doubleValue())//
|
||||
.as(ErrorMessageHelper.wrongAmountInRepaymentScheduleInAdvance(
|
||||
repaymentSchedule.getTotalPaidInAdvance().doubleValue(), Double.valueOf(expectedValue)))//
|
||||
.isEqualTo(Double.valueOf(expectedValue));//
|
||||
case "Late" -> assertThat(repaymentSchedule.getTotalPaidLate().doubleValue())//
|
||||
.as(ErrorMessageHelper.wrongAmountInRepaymentScheduleLate(repaymentSchedule.getTotalPaidLate().doubleValue(),
|
||||
Double.valueOf(expectedValue)))//
|
||||
.isEqualTo(Double.valueOf(expectedValue));//
|
||||
case "Waived" -> assertThat(repaymentSchedule.getTotalWaived().doubleValue())//
|
||||
.as(ErrorMessageHelper.wrongAmountInRepaymentScheduleWaived(repaymentSchedule.getTotalWaived().doubleValue(),
|
||||
Double.valueOf(expectedValue)))//
|
||||
.isEqualTo(Double.valueOf(expectedValue));//
|
||||
case "Outstanding" -> assertThat(repaymentSchedule.getTotalOutstanding().doubleValue())//
|
||||
.as(ErrorMessageHelper.wrongAmountInRepaymentScheduleOutstanding(
|
||||
repaymentSchedule.getTotalOutstanding().doubleValue(), Double.valueOf(expectedValue)))//
|
||||
.isEqualTo(Double.valueOf(expectedValue));//
|
||||
}
|
||||
}
|
||||
return actualValues;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
@@ -48,6 +48,7 @@ public abstract class TestContextKey {
|
||||
public static final String LOAN_REFUND_RESPONSE = "loanRefundResponse";
|
||||
public static final String LOAN_REAGING_RESPONSE = "loanReAgingResponse";
|
||||
public static final String LOAN_REAGING_UNDO_RESPONSE = "loanReAgingUndoResponse";
|
||||
public static final String LOAN_REAGING_PREVIEW_RESPONSE = "loanReAgingPreviewResponse";
|
||||
public static final String LOAN_REAMORTIZATION_RESPONSE = "loanReAmortizationResponse";
|
||||
public static final String LOAN_REAMORTIZATION_UNDO_RESPONSE = "loanReAmortizationUndoResponse";
|
||||
public static final String BUSINESS_DATE_RESPONSE = "businessDateResponse";
|
||||
|
||||
Reference in New Issue
Block a user