FINERACT-2081: Add all loan term validations to loan details
This commit is contained in:
committed by
Arnold Gálovics
parent
fe16b61c72
commit
25866edfc9
@@ -607,6 +607,17 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"default": null,
|
||||||
|
"name": "loanTermVariations",
|
||||||
|
"type": [
|
||||||
|
"null",
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"items": "org.apache.fineract.avro.loan.v1.LoanTermVariationsDataV1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"default": null,
|
"default": null,
|
||||||
"name": "clientActiveLoanOptions",
|
"name": "clientActiveLoanOptions",
|
||||||
|
|||||||
+1
@@ -49,6 +49,7 @@ public final class DataTableApiConstant {
|
|||||||
public static final String linkedAccountAssociateParamName = "linkedAccount";
|
public static final String linkedAccountAssociateParamName = "linkedAccount";
|
||||||
public static final String multiDisburseDetailsAssociateParamName = "multiDisburseDetails";
|
public static final String multiDisburseDetailsAssociateParamName = "multiDisburseDetails";
|
||||||
public static final String futureScheduleAssociateParamName = "futureSchedule";
|
public static final String futureScheduleAssociateParamName = "futureSchedule";
|
||||||
|
public static final String loanTermVariationsAssociateParamName = "loanTermVariations";
|
||||||
public static final String meetingAssociateParamName = "meeting";
|
public static final String meetingAssociateParamName = "meeting";
|
||||||
public static final String emiAmountVariationsAssociateParamName = "emiAmountVariations";
|
public static final String emiAmountVariationsAssociateParamName = "emiAmountVariations";
|
||||||
public static final String collectionAssociateParamName = "collection";
|
public static final String collectionAssociateParamName = "collection";
|
||||||
|
|||||||
+15
@@ -24,6 +24,7 @@ import java.time.LocalDate;
|
|||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.fineract.client.models.BatchResponse;
|
import org.apache.fineract.client.models.BatchResponse;
|
||||||
import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse;
|
import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse;
|
||||||
@@ -864,4 +865,18 @@ public final class ErrorMessageHelper {
|
|||||||
return String.format("Wrong value in LoanDeteils/fixedLength. %nActual value is: %s %nExpected Value is: %s", actualToStr,
|
return String.format("Wrong value in LoanDeteils/fixedLength. %nActual value is: %s %nExpected Value is: %s", actualToStr,
|
||||||
expectedToStr);
|
expectedToStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String wrongValueInLineInLoanTermVariations(final int line, final List<List<String>> actual,
|
||||||
|
final List<String> expected) {
|
||||||
|
final String actualValues = actual.stream().map(List::toString).collect(Collectors.joining(System.lineSeparator()));
|
||||||
|
|
||||||
|
return String.format(
|
||||||
|
"%nWrong value in loan term variations tab line %d.%nActual values in line (with the same term variation applicable from) are:%n%s%nExpected values in line:%n%s",
|
||||||
|
line, actualValues, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String wrongNumberOfLinesInLoanTermVariations(final int actual, final int expected) {
|
||||||
|
return String.format("Number of lines in loan term variations is not correct. Actual value is: %d - Expected value is: %d", actual,
|
||||||
|
expected);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+212
-82
@@ -21,6 +21,7 @@ package org.apache.fineract.test.stepdef.loan;
|
|||||||
import static org.apache.fineract.test.data.TransactionProcessingStrategyCode.ADVANCED_PAYMENT_ALLOCATION;
|
import static org.apache.fineract.test.data.TransactionProcessingStrategyCode.ADVANCED_PAYMENT_ALLOCATION;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.awaitility.Awaitility.await;
|
import static org.awaitility.Awaitility.await;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
@@ -54,6 +55,7 @@ import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
|
|||||||
import org.apache.fineract.client.models.GetLoansLoanIdDelinquencySummary;
|
import org.apache.fineract.client.models.GetLoansLoanIdDelinquencySummary;
|
||||||
import org.apache.fineract.client.models.GetLoansLoanIdLoanChargeData;
|
import org.apache.fineract.client.models.GetLoansLoanIdLoanChargeData;
|
||||||
import org.apache.fineract.client.models.GetLoansLoanIdLoanChargePaidByData;
|
import org.apache.fineract.client.models.GetLoansLoanIdLoanChargePaidByData;
|
||||||
|
import org.apache.fineract.client.models.GetLoansLoanIdLoanTermVariations;
|
||||||
import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod;
|
import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod;
|
||||||
import org.apache.fineract.client.models.GetLoansLoanIdRepaymentSchedule;
|
import org.apache.fineract.client.models.GetLoansLoanIdRepaymentSchedule;
|
||||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||||
@@ -369,74 +371,15 @@ public class LoanStepDef extends AbstractStepDef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@When("Admin creates a fully customized loan with the following data:")
|
@When("Admin creates a fully customized loan with the following data:")
|
||||||
public void createFullyCustomizedLoan(DataTable table) throws IOException {
|
public void createFullyCustomizedLoan(final DataTable table) throws IOException {
|
||||||
List<List<String>> data = table.asLists();
|
final List<List<String>> data = table.asLists();
|
||||||
List<String> loanData = data.get(1);
|
createCustomizedLoan(data.get(1), false);
|
||||||
String loanProduct = loanData.get(0);
|
}
|
||||||
String submitDate = loanData.get(1);
|
|
||||||
String principal = loanData.get(2);
|
|
||||||
BigDecimal interestRate = new BigDecimal(loanData.get(3));
|
|
||||||
String interestType = loanData.get(4);
|
|
||||||
String interestCalculationPeriod = loanData.get(5);
|
|
||||||
String amortizationType = loanData.get(6);
|
|
||||||
Integer loanTermFrequency = Integer.valueOf(loanData.get(7));
|
|
||||||
String loanTermFrequencyType = loanData.get(8);
|
|
||||||
Integer repaymentFrequency = Integer.valueOf(loanData.get(9));
|
|
||||||
String repaymentFrequencyType = loanData.get(10);
|
|
||||||
Integer numberOfRepayments = Integer.valueOf(loanData.get(11));
|
|
||||||
Integer graceOnPrincipalPayment = Integer.valueOf(loanData.get(12));
|
|
||||||
Integer graceOnInterestPayment = Integer.valueOf(loanData.get(13));
|
|
||||||
Integer graceOnInterestCharged = Integer.valueOf(loanData.get(14));
|
|
||||||
String transactionProcessingStrategyCode = loanData.get(15);
|
|
||||||
|
|
||||||
Response<PostClientsResponse> clientResponse = testContext().get(TestContextKey.CLIENT_CREATE_RESPONSE);
|
@When("Admin creates a fully customized loan with emi and the following data:")
|
||||||
Long clientId = clientResponse.body().getClientId();
|
public void createFullyCustomizedLoanWithEmi(final DataTable table) throws IOException {
|
||||||
|
final List<List<String>> data = table.asLists();
|
||||||
DefaultLoanProduct product = DefaultLoanProduct.valueOf(loanProduct);
|
createCustomizedLoan(data.get(1), true);
|
||||||
Long loanProductId = loanProductResolver.resolve(product);
|
|
||||||
|
|
||||||
LoanTermFrequencyType termFrequencyType = LoanTermFrequencyType.valueOf(loanTermFrequencyType);
|
|
||||||
Integer loanTermFrequencyTypeValue = termFrequencyType.getValue();
|
|
||||||
|
|
||||||
RepaymentFrequencyType repaymentFrequencyType1 = RepaymentFrequencyType.valueOf(repaymentFrequencyType);
|
|
||||||
Integer repaymentFrequencyTypeValue = repaymentFrequencyType1.getValue();
|
|
||||||
|
|
||||||
InterestType interestType1 = InterestType.valueOf(interestType);
|
|
||||||
Integer interestTypeValue = interestType1.getValue();
|
|
||||||
|
|
||||||
InterestCalculationPeriodTime interestCalculationPeriod1 = InterestCalculationPeriodTime.valueOf(interestCalculationPeriod);
|
|
||||||
Integer interestCalculationPeriodValue = interestCalculationPeriod1.getValue();
|
|
||||||
|
|
||||||
AmortizationType amortizationType1 = AmortizationType.valueOf(amortizationType);
|
|
||||||
Integer amortizationTypeValue = amortizationType1.getValue();
|
|
||||||
|
|
||||||
TransactionProcessingStrategyCode processingStrategyCode = TransactionProcessingStrategyCode
|
|
||||||
.valueOf(transactionProcessingStrategyCode);
|
|
||||||
String transactionProcessingStrategyCodeValue = processingStrategyCode.getValue();
|
|
||||||
|
|
||||||
PostLoansRequest loansRequest = loanRequestFactory.defaultLoansRequest(clientId)//
|
|
||||||
.productId(loanProductId)//
|
|
||||||
.principal(new BigDecimal(principal))//
|
|
||||||
.interestRatePerPeriod(interestRate)//
|
|
||||||
.interestType(interestTypeValue)//
|
|
||||||
.interestCalculationPeriodType(interestCalculationPeriodValue)//
|
|
||||||
.amortizationType(amortizationTypeValue)//
|
|
||||||
.loanTermFrequency(loanTermFrequency)//
|
|
||||||
.loanTermFrequencyType(loanTermFrequencyTypeValue)//
|
|
||||||
.numberOfRepayments(numberOfRepayments)//
|
|
||||||
.repaymentEvery(repaymentFrequency)//
|
|
||||||
.repaymentFrequencyType(repaymentFrequencyTypeValue)//
|
|
||||||
.submittedOnDate(submitDate)//
|
|
||||||
.expectedDisbursementDate(submitDate)//
|
|
||||||
.graceOnPrincipalPayment(graceOnPrincipalPayment)//
|
|
||||||
.graceOnInterestPayment(graceOnInterestPayment)//
|
|
||||||
.graceOnInterestPayment(graceOnInterestCharged).transactionProcessingStrategyCode(transactionProcessingStrategyCodeValue);//
|
|
||||||
|
|
||||||
Response<PostLoansResponse> response = loansApi.calculateLoanScheduleOrSubmitLoanApplication(loansRequest, "").execute();
|
|
||||||
testContext().set(TestContextKey.LOAN_CREATE_RESPONSE, response);
|
|
||||||
ErrorHelper.checkSuccessfulApiCall(response);
|
|
||||||
|
|
||||||
eventCheckHelper.createLoanEventCheck(response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@When("Admin creates a fully customized loan with fixed length {int} and with the following data:")
|
@When("Admin creates a fully customized loan with fixed length {int} and with the following data:")
|
||||||
@@ -842,24 +785,36 @@ public class LoanStepDef extends AbstractStepDef {
|
|||||||
|
|
||||||
@And("Admin successfully disburse the loan on {string} with {string} EUR transaction amount")
|
@And("Admin successfully disburse the loan on {string} with {string} EUR transaction amount")
|
||||||
public void disburseLoan(String actualDisbursementDate, String transactionAmount) throws IOException {
|
public void disburseLoan(String actualDisbursementDate, String transactionAmount) throws IOException {
|
||||||
Response<PostLoansResponse> loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
final Response<PostLoansResponse> loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
||||||
long loanId = loanResponse.body().getLoanId();
|
assertNotNull(loanResponse.body());
|
||||||
PostLoansLoanIdRequest disburseRequest = LoanRequestFactory.defaultLoanDisburseRequest()
|
final long loanId = loanResponse.body().getLoanId();
|
||||||
|
final PostLoansLoanIdRequest disburseRequest = LoanRequestFactory.defaultLoanDisburseRequest()
|
||||||
.actualDisbursementDate(actualDisbursementDate).transactionAmount(new BigDecimal(transactionAmount));
|
.actualDisbursementDate(actualDisbursementDate).transactionAmount(new BigDecimal(transactionAmount));
|
||||||
|
performLoanDisbursementAndVerifyStatus(loanId, disburseRequest);
|
||||||
|
}
|
||||||
|
|
||||||
Response<PostLoansLoanIdResponse> loanDisburseResponse = loansApi.stateTransitions(loanId, disburseRequest, "disburse").execute();
|
@And("Admin successfully disburse the loan on {string} with {string} EUR transaction amount and {string} fixed emi amount")
|
||||||
testContext().set(TestContextKey.LOAN_DISBURSE_RESPONSE, loanDisburseResponse);
|
public void disburseLoanWithFixedEmiAmount(final String actualDisbursementDate, final String transactionAmount,
|
||||||
ErrorHelper.checkSuccessfulApiCall(loanDisburseResponse);
|
final String fixedEmiAmount) throws IOException {
|
||||||
Long statusActual = loanDisburseResponse.body().getChanges().getStatus().getId();
|
final Response<PostLoansResponse> loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
||||||
|
assertNotNull(loanResponse.body());
|
||||||
|
final long loanId = loanResponse.body().getLoanId();
|
||||||
|
final PostLoansLoanIdRequest disburseRequest = LoanRequestFactory.defaultLoanDisburseRequest()
|
||||||
|
.actualDisbursementDate(actualDisbursementDate).transactionAmount(new BigDecimal(transactionAmount))
|
||||||
|
.fixedEmiAmount(new BigDecimal(fixedEmiAmount));
|
||||||
|
performLoanDisbursementAndVerifyStatus(loanId, disburseRequest);
|
||||||
|
}
|
||||||
|
|
||||||
Response<GetLoansLoanIdResponse> loanDetails = loansApi.retrieveLoan(loanId, false, "", "", "").execute();
|
@And("Admin successfully disburse the loan on {string} with {string} EUR transaction amount, {string} EUR fixed emi amount and adjust repayment date on {string}")
|
||||||
Long statusExpected = Long.valueOf(loanDetails.body().getStatus().getId());
|
public void disburseLoanWithFixedEmiAmountAndAdjustRepaymentDate(final String actualDisbursementDate, final String transactionAmount,
|
||||||
|
final String fixedEmiAmount, final String adjustRepaymentDate) throws IOException {
|
||||||
assertThat(statusActual)//
|
final Response<PostLoansResponse> loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
||||||
.as(ErrorMessageHelper.wrongLoanStatus(Math.toIntExact(statusActual), Math.toIntExact(statusExpected)))//
|
assertNotNull(loanResponse.body());
|
||||||
.isEqualTo(statusExpected);//
|
final long loanId = loanResponse.body().getLoanId();
|
||||||
eventCheckHelper.disburseLoanEventCheck(loanDisburseResponse);
|
final PostLoansLoanIdRequest disburseRequest = LoanRequestFactory.defaultLoanDisburseRequest()
|
||||||
eventCheckHelper.loanDisbursalTransactionEventCheck(loanDisburseResponse);
|
.actualDisbursementDate(actualDisbursementDate).transactionAmount(new BigDecimal(transactionAmount))
|
||||||
|
.fixedEmiAmount(new BigDecimal(fixedEmiAmount)).adjustRepaymentDate(adjustRepaymentDate);
|
||||||
|
performLoanDisbursementAndVerifyStatus(loanId, disburseRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
@And("Admin successfully disburse the second loan on {string} with {string} EUR transaction amount")
|
@And("Admin successfully disburse the second loan on {string} with {string} EUR transaction amount")
|
||||||
@@ -1939,6 +1894,155 @@ public class LoanStepDef extends AbstractStepDef {
|
|||||||
.isEqualTo(ErrorMessageHelper.disbursePastDateFailure((int) loanId, futureApproveDateISO));
|
.isEqualTo(ErrorMessageHelper.disbursePastDateFailure((int) loanId, futureApproveDateISO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Then("Loan emi amount variations has {int} variation, with the following data:")
|
||||||
|
public void loanEmiAmountVariationsCheck(final int linesExpected, final DataTable table) throws IOException {
|
||||||
|
final Response<PostLoansResponse> loanCreateResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
||||||
|
assertNotNull(loanCreateResponse.body());
|
||||||
|
final long loanId = loanCreateResponse.body().getLoanId();
|
||||||
|
|
||||||
|
final Response<GetLoansLoanIdResponse> loanDetailsResponse = loansApi.retrieveLoan(loanId, false, "all", "", "").execute();
|
||||||
|
ErrorHelper.checkSuccessfulApiCall(loanDetailsResponse);
|
||||||
|
|
||||||
|
final List<GetLoansLoanIdLoanTermVariations> emiAmountVariations = loanDetailsResponse.body().getEmiAmountVariations();
|
||||||
|
|
||||||
|
final List<List<String>> data = table.asLists();
|
||||||
|
assertNotNull(emiAmountVariations);
|
||||||
|
final int linesActual = emiAmountVariations.size();
|
||||||
|
data.stream().skip(1) // skip headers
|
||||||
|
.forEach(expectedValues -> {
|
||||||
|
final List<List<String>> actualValuesList = emiAmountVariations.stream()
|
||||||
|
.map(emi -> fetchValuesOfLoanTermVariations(data.get(0), emi)).collect(Collectors.toList());
|
||||||
|
|
||||||
|
final boolean containsExpectedValues = actualValuesList.stream()
|
||||||
|
.anyMatch(actualValues -> actualValues.equals(expectedValues));
|
||||||
|
assertThat(containsExpectedValues).as(ErrorMessageHelper
|
||||||
|
.wrongValueInLineInLoanTermVariations(data.indexOf(expectedValues), actualValuesList, expectedValues)).isTrue();
|
||||||
|
|
||||||
|
assertThat(linesActual).as(ErrorMessageHelper.wrongNumberOfLinesInLoanTermVariations(linesActual, linesExpected))
|
||||||
|
.isEqualTo(linesExpected);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Then("Loan term variations has {int} variation, with the following data:")
|
||||||
|
public void loanTermVariationsCheck(final int linesExpected, final DataTable table) throws IOException {
|
||||||
|
final Response<PostLoansResponse> loanCreateResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
||||||
|
assertNotNull(loanCreateResponse.body());
|
||||||
|
final long loanId = loanCreateResponse.body().getLoanId();
|
||||||
|
|
||||||
|
final Response<GetLoansLoanIdResponse> loanDetailsResponse = loansApi.retrieveLoan(loanId, false, "loanTermVariations", "", "")
|
||||||
|
.execute();
|
||||||
|
ErrorHelper.checkSuccessfulApiCall(loanDetailsResponse);
|
||||||
|
|
||||||
|
final List<GetLoansLoanIdLoanTermVariations> loanTermVariations = loanDetailsResponse.body().getLoanTermVariations();
|
||||||
|
assertNotNull(loanTermVariations);
|
||||||
|
|
||||||
|
final List<List<String>> data = table.asLists();
|
||||||
|
final int linesActual = loanTermVariations.size();
|
||||||
|
data.stream().skip(1) // skip headers
|
||||||
|
.forEach(expectedValues -> {
|
||||||
|
final String expectedTermTypeId = expectedValues.get(0);
|
||||||
|
|
||||||
|
final List<List<String>> actualValuesList = loanTermVariations.stream().filter(loanTerm -> {
|
||||||
|
assertNotNull(loanTerm.getTermType());
|
||||||
|
return expectedTermTypeId.equals(String.valueOf(loanTerm.getTermType().getId()));
|
||||||
|
}).map(loanTerm -> fetchValuesOfLoanTermVariations(data.get(0), loanTerm)).collect(Collectors.toList());
|
||||||
|
|
||||||
|
final boolean containsExpectedValues = actualValuesList.stream()
|
||||||
|
.anyMatch(actualValues -> actualValues.equals(expectedValues));
|
||||||
|
assertThat(containsExpectedValues).as(ErrorMessageHelper
|
||||||
|
.wrongValueInLineInLoanTermVariations(data.indexOf(expectedValues), actualValuesList, expectedValues)).isTrue();
|
||||||
|
|
||||||
|
assertThat(linesActual).as(ErrorMessageHelper.wrongNumberOfLinesInLoanTermVariations(linesActual, linesExpected))
|
||||||
|
.isEqualTo(linesExpected);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createCustomizedLoan(final List<String> loanData, final boolean withEmi) throws IOException {
|
||||||
|
final String loanProduct = loanData.get(0);
|
||||||
|
final String submitDate = loanData.get(1);
|
||||||
|
final String principal = loanData.get(2);
|
||||||
|
final BigDecimal interestRate = new BigDecimal(loanData.get(3));
|
||||||
|
final String interestType = loanData.get(4);
|
||||||
|
final String interestCalculationPeriod = loanData.get(5);
|
||||||
|
final String amortizationType = loanData.get(6);
|
||||||
|
final Integer loanTermFrequency = Integer.valueOf(loanData.get(7));
|
||||||
|
final String loanTermFrequencyType = loanData.get(8);
|
||||||
|
final Integer repaymentFrequency = Integer.valueOf(loanData.get(9));
|
||||||
|
final String repaymentFrequencyType = loanData.get(10);
|
||||||
|
final Integer numberOfRepayments = Integer.valueOf(loanData.get(11));
|
||||||
|
final Integer graceOnPrincipalPayment = Integer.valueOf(loanData.get(12));
|
||||||
|
final Integer graceOnInterestPayment = Integer.valueOf(loanData.get(13));
|
||||||
|
final Integer graceOnInterestCharged = Integer.valueOf(loanData.get(14));
|
||||||
|
final String transactionProcessingStrategyCode = loanData.get(15);
|
||||||
|
|
||||||
|
final Response<PostClientsResponse> clientResponse = testContext().get(TestContextKey.CLIENT_CREATE_RESPONSE);
|
||||||
|
final Long clientId = clientResponse.body().getClientId();
|
||||||
|
|
||||||
|
final DefaultLoanProduct product = DefaultLoanProduct.valueOf(loanProduct);
|
||||||
|
final Long loanProductId = loanProductResolver.resolve(product);
|
||||||
|
|
||||||
|
final LoanTermFrequencyType termFrequencyType = LoanTermFrequencyType.valueOf(loanTermFrequencyType);
|
||||||
|
final Integer loanTermFrequencyTypeValue = termFrequencyType.getValue();
|
||||||
|
|
||||||
|
final RepaymentFrequencyType repaymentFrequencyType1 = RepaymentFrequencyType.valueOf(repaymentFrequencyType);
|
||||||
|
final Integer repaymentFrequencyTypeValue = repaymentFrequencyType1.getValue();
|
||||||
|
|
||||||
|
final InterestType interestType1 = InterestType.valueOf(interestType);
|
||||||
|
final Integer interestTypeValue = interestType1.getValue();
|
||||||
|
|
||||||
|
final InterestCalculationPeriodTime interestCalculationPeriod1 = InterestCalculationPeriodTime.valueOf(interestCalculationPeriod);
|
||||||
|
final Integer interestCalculationPeriodValue = interestCalculationPeriod1.getValue();
|
||||||
|
|
||||||
|
final AmortizationType amortizationType1 = AmortizationType.valueOf(amortizationType);
|
||||||
|
final Integer amortizationTypeValue = amortizationType1.getValue();
|
||||||
|
|
||||||
|
final TransactionProcessingStrategyCode processingStrategyCode = TransactionProcessingStrategyCode
|
||||||
|
.valueOf(transactionProcessingStrategyCode);
|
||||||
|
final String transactionProcessingStrategyCodeValue = processingStrategyCode.getValue();
|
||||||
|
|
||||||
|
final PostLoansRequest loansRequest = loanRequestFactory.defaultLoansRequest(clientId).productId(loanProductId)
|
||||||
|
.principal(new BigDecimal(principal)).interestRatePerPeriod(interestRate).interestType(interestTypeValue)
|
||||||
|
.interestCalculationPeriodType(interestCalculationPeriodValue).amortizationType(amortizationTypeValue)
|
||||||
|
.loanTermFrequency(loanTermFrequency).loanTermFrequencyType(loanTermFrequencyTypeValue)
|
||||||
|
.numberOfRepayments(numberOfRepayments).repaymentEvery(repaymentFrequency)
|
||||||
|
.repaymentFrequencyType(repaymentFrequencyTypeValue).submittedOnDate(submitDate).expectedDisbursementDate(submitDate)
|
||||||
|
.graceOnPrincipalPayment(graceOnPrincipalPayment).graceOnInterestPayment(graceOnInterestPayment)
|
||||||
|
.graceOnInterestPayment(graceOnInterestCharged).transactionProcessingStrategyCode(transactionProcessingStrategyCodeValue);
|
||||||
|
|
||||||
|
if (withEmi) {
|
||||||
|
loansRequest.fixedEmiAmount(new BigDecimal(555));
|
||||||
|
}
|
||||||
|
|
||||||
|
final Response<PostLoansResponse> response = loansApi.calculateLoanScheduleOrSubmitLoanApplication(loansRequest, "").execute();
|
||||||
|
testContext().set(TestContextKey.LOAN_CREATE_RESPONSE, response);
|
||||||
|
ErrorHelper.checkSuccessfulApiCall(response);
|
||||||
|
|
||||||
|
eventCheckHelper.createLoanEventCheck(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performLoanDisbursementAndVerifyStatus(final long loanId, final PostLoansLoanIdRequest disburseRequest)
|
||||||
|
throws IOException {
|
||||||
|
final Response<PostLoansLoanIdResponse> loanDisburseResponse = loansApi.stateTransitions(loanId, disburseRequest, "disburse")
|
||||||
|
.execute();
|
||||||
|
testContext().set(TestContextKey.LOAN_DISBURSE_RESPONSE, loanDisburseResponse);
|
||||||
|
ErrorHelper.checkSuccessfulApiCall(loanDisburseResponse);
|
||||||
|
assertNotNull(loanDisburseResponse.body());
|
||||||
|
assertNotNull(loanDisburseResponse.body().getChanges());
|
||||||
|
assertNotNull(loanDisburseResponse.body().getChanges().getStatus());
|
||||||
|
final Long statusActual = loanDisburseResponse.body().getChanges().getStatus().getId();
|
||||||
|
assertNotNull(statusActual);
|
||||||
|
|
||||||
|
final Response<GetLoansLoanIdResponse> loanDetails = loansApi.retrieveLoan(loanId, false, "", "", "").execute();
|
||||||
|
assertNotNull(loanDetails.body());
|
||||||
|
assertNotNull(loanDetails.body().getStatus());
|
||||||
|
final Long statusExpected = Long.valueOf(loanDetails.body().getStatus().getId());
|
||||||
|
|
||||||
|
assertThat(statusActual).as(ErrorMessageHelper.wrongLoanStatus(Math.toIntExact(statusActual), Math.toIntExact(statusExpected)))
|
||||||
|
.isEqualTo(statusExpected);
|
||||||
|
eventCheckHelper.disburseLoanEventCheck(loanDisburseResponse);
|
||||||
|
eventCheckHelper.loanDisbursalTransactionEventCheck(loanDisburseResponse);
|
||||||
|
}
|
||||||
|
|
||||||
private LoanStatusEnumDataV1 getExpectedStatus(String loanStatus) {
|
private LoanStatusEnumDataV1 getExpectedStatus(String loanStatus) {
|
||||||
LoanStatusEnumDataV1 result = new LoanStatusEnumDataV1();
|
LoanStatusEnumDataV1 result = new LoanStatusEnumDataV1();
|
||||||
switch (loanStatus) {
|
switch (loanStatus) {
|
||||||
@@ -2137,4 +2241,30 @@ public class LoanStepDef extends AbstractStepDef {
|
|||||||
}
|
}
|
||||||
return actualValues;
|
return actualValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressFBWarnings("SF_SWITCH_NO_DEFAULT")
|
||||||
|
private List<String> fetchValuesOfLoanTermVariations(final List<String> header, final GetLoansLoanIdLoanTermVariations emiVariation) {
|
||||||
|
final List<String> actualValues = new ArrayList<>();
|
||||||
|
assertNotNull(emiVariation.getTermType());
|
||||||
|
for (String headerName : header) {
|
||||||
|
switch (headerName) {
|
||||||
|
case "Term Type Id" -> actualValues
|
||||||
|
.add(emiVariation.getTermType().getId() == null ? null : String.valueOf(emiVariation.getTermType().getId()));
|
||||||
|
case "Term Type Code" ->
|
||||||
|
actualValues.add(emiVariation.getTermType().getCode() == null ? null : emiVariation.getTermType().getCode());
|
||||||
|
case "Term Type Value" ->
|
||||||
|
actualValues.add(emiVariation.getTermType().getValue() == null ? null : emiVariation.getTermType().getValue());
|
||||||
|
case "Applicable From" -> actualValues.add(emiVariation.getTermVariationApplicableFrom() == null ? null
|
||||||
|
: FORMATTER.format(emiVariation.getTermVariationApplicableFrom()));
|
||||||
|
case "Decimal Value" ->
|
||||||
|
actualValues.add(emiVariation.getDecimalValue() == null ? null : String.valueOf(emiVariation.getDecimalValue()));
|
||||||
|
case "Date Value" ->
|
||||||
|
actualValues.add(emiVariation.getDateValue() == null ? null : FORMATTER.format(emiVariation.getDateValue()));
|
||||||
|
case "Is Specific To Installment" -> actualValues.add(String.valueOf(emiVariation.getIsSpecificToInstallment()));
|
||||||
|
case "Is Processed" ->
|
||||||
|
actualValues.add(emiVariation.getIsProcessed() == null ? null : String.valueOf(emiVariation.getIsProcessed()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return actualValues;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5728,3 +5728,32 @@ Feature: Loan
|
|||||||
| 5 | 31 | 01 June 2024 | | 16.93 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
| 5 | 31 | 01 June 2024 | | 16.93 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 |
|
||||||
| 6 | 30 | 01 July 2024 | | 0.0 | 16.93 | 0.1 | 0.0 | 0.0 | 17.03 | 0.0 | 0.0 | 0.0 | 17.03 |
|
| 6 | 30 | 01 July 2024 | | 0.0 | 16.93 | 0.1 | 0.0 | 0.0 | 17.03 | 0.0 | 0.0 | 0.0 | 17.03 |
|
||||||
When Admin removes "LOAN_INTEREST_RECALCULATION" business step into LOAN_CLOSE_OF_BUSINESS workflow
|
When Admin removes "LOAN_INTEREST_RECALCULATION" business step into LOAN_CLOSE_OF_BUSINESS workflow
|
||||||
|
|
||||||
|
Scenario: Loan Details Emi Amount Variations - AssociationsAll
|
||||||
|
Given Global configuration "is-interest-to-be-recovered-first-when-greater-than-emi" is enabled
|
||||||
|
Given Global configuration "enable-business-date" is enabled
|
||||||
|
When Admin sets the business date to "1 January 2023"
|
||||||
|
When Admin creates a client with random data
|
||||||
|
When Admin creates a fully customized loan with emi and the following data:
|
||||||
|
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
|
||||||
|
| LP1_INTEREST_DECLINING_BALANCE_SAR_RECALCULATION_SAME_AS_REPAYMENT_COMPOUNDING_NONE_MULTIDISB | 01 January 2023 | 10000 | 12 | DECLINING_BALANCE | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | PENALTIES_FEES_INTEREST_PRINCIPAL_ORDER |
|
||||||
|
And Admin successfully approves the loan on "1 January 2023" with "100" amount and expected disbursement date on "1 January 2023"
|
||||||
|
When Admin successfully disburse the loan on "1 January 2023" with "100" EUR transaction amount and "50" fixed emi amount
|
||||||
|
Then Loan emi amount variations has 1 variation, with the following data:
|
||||||
|
| Term Type Id | Term Type Code | Term Type Value | Applicable From | Decimal Value | Date Value | Is Specific To Installment | Is Processed |
|
||||||
|
| 1 | loanTermType.emiAmount | emiAmount | 01 January 2023 | 50.0 | | false | |
|
||||||
|
|
||||||
|
Scenario: Loan Details Loan Term Variations
|
||||||
|
Given Global configuration "is-interest-to-be-recovered-first-when-greater-than-emi" is enabled
|
||||||
|
Given Global configuration "enable-business-date" is enabled
|
||||||
|
When Admin sets the business date to "1 January 2023"
|
||||||
|
When Admin creates a client with random data
|
||||||
|
When Admin creates a fully customized loan with emi and the following data:
|
||||||
|
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
|
||||||
|
| LP1_INTEREST_DECLINING_BALANCE_SAR_RECALCULATION_SAME_AS_REPAYMENT_COMPOUNDING_NONE_MULTIDISB | 01 January 2023 | 10000 | 12 | DECLINING_BALANCE | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | PENALTIES_FEES_INTEREST_PRINCIPAL_ORDER |
|
||||||
|
And Admin successfully approves the loan on "1 January 2023" with "100" amount and expected disbursement date on "1 January 2023"
|
||||||
|
When Admin successfully disburse the loan on "1 January 2023" with "100" EUR transaction amount, "50" EUR fixed emi amount and adjust repayment date on "15 January 2023"
|
||||||
|
Then Loan term variations has 2 variation, with the following data:
|
||||||
|
| Term Type Id | Term Type Code | Term Type Value | Applicable From | Decimal Value | Date Value | Is Specific To Installment | Is Processed |
|
||||||
|
| 1 | loanTermType.emiAmount | emiAmount | 01 January 2023 | 50.0 | | false | |
|
||||||
|
| 4 | loanTermType.dueDate | dueDate | 01 February 2023 | 50.0 | 15 January 2023 | false | |
|
||||||
+11
@@ -24,6 +24,7 @@ import lombok.Getter;
|
|||||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class LoanTermVariationsData implements Comparable<LoanTermVariationsData> {
|
public class LoanTermVariationsData implements Comparable<LoanTermVariationsData> {
|
||||||
@@ -46,6 +47,16 @@ public class LoanTermVariationsData implements Comparable<LoanTermVariationsData
|
|||||||
this.isSpecificToInstallment = isSpecificToInstallment;
|
this.isSpecificToInstallment = isSpecificToInstallment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LoanTermVariationsData(final Long id, final Integer termType, final LocalDate termVariationApplicableFrom,
|
||||||
|
final BigDecimal decimalValue, final LocalDate dateValue, final boolean isSpecificToInstallment) {
|
||||||
|
this.id = id;
|
||||||
|
this.termType = LoanEnumerations.loanVariationType(LoanTermVariationType.fromInt(termType));
|
||||||
|
this.termVariationApplicableFrom = termVariationApplicableFrom;
|
||||||
|
this.decimalValue = decimalValue;
|
||||||
|
this.dateValue = dateValue;
|
||||||
|
this.isSpecificToInstallment = isSpecificToInstallment;
|
||||||
|
}
|
||||||
|
|
||||||
public LoanTermVariationsData(final EnumOptionData termType, final LocalDate termVariationApplicableFrom, final BigDecimal decimalValue,
|
public LoanTermVariationsData(final EnumOptionData termType, final LocalDate termVariationApplicableFrom, final BigDecimal decimalValue,
|
||||||
LocalDate dateValue, final boolean isSpecificToInstallment) {
|
LocalDate dateValue, final boolean isSpecificToInstallment) {
|
||||||
this.id = null;
|
this.id = null;
|
||||||
|
|||||||
+5
-9
@@ -5366,16 +5366,12 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
return isForeClosure;
|
return isForeClosure;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<LoanTermVariations> getActiveLoanTermVariations() {
|
public List<LoanTermVariations> getActiveLoanTermVariations() {
|
||||||
Set<LoanTermVariations> retData = new HashSet<>();
|
if (this.loanTermVariations == null) {
|
||||||
if (this.loanTermVariations != null && !this.loanTermVariations.isEmpty()) {
|
return new ArrayList<>();
|
||||||
for (LoanTermVariations loanTermVariations : this.loanTermVariations) {
|
|
||||||
if (loanTermVariations.isActive()) {
|
|
||||||
retData.add(loanTermVariations);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return !retData.isEmpty() ? retData : null;
|
|
||||||
|
return this.loanTermVariations.stream().filter(LoanTermVariations::isActive).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isTopup() {
|
public boolean isTopup() {
|
||||||
|
|||||||
+20
-2
@@ -19,6 +19,7 @@
|
|||||||
package org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain;
|
package org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
@@ -28,7 +29,24 @@ import org.springframework.data.repository.query.Param;
|
|||||||
public interface LoanTermVariationsRepository
|
public interface LoanTermVariationsRepository
|
||||||
extends JpaRepository<LoanTermVariations, Long>, JpaSpecificationExecutor<LoanTermVariations> {
|
extends JpaRepository<LoanTermVariations, Long>, JpaSpecificationExecutor<LoanTermVariations> {
|
||||||
|
|
||||||
@Query("select lrr from LoanTermVariations lrr where lrr.loan.id = :loanId")
|
@Query("""
|
||||||
List<LoanTermVariations> findAllLoanTermVariationsByLoanId(@Param("loanId") Long loanId);
|
select new org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData(
|
||||||
|
ltv.id, ltv.termType, ltv.termApplicableFrom, ltv.decimalValue, ltv.dateValue, ltv.isSpecificToInstallment
|
||||||
|
)
|
||||||
|
from LoanTermVariations ltv
|
||||||
|
where ltv.loan.id = :loanId
|
||||||
|
order by ltv.termApplicableFrom
|
||||||
|
""")
|
||||||
|
List<LoanTermVariationsData> findLoanTermVariationsByLoanId(@Param("loanId") long loanId);
|
||||||
|
|
||||||
|
@Query("""
|
||||||
|
select new org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData(
|
||||||
|
ltv.id, ltv.termType, ltv.termApplicableFrom, ltv.decimalValue, ltv.dateValue, ltv.isSpecificToInstallment
|
||||||
|
)
|
||||||
|
from LoanTermVariations ltv
|
||||||
|
where ltv.loan.id = :loanId and ltv.termType = :termType
|
||||||
|
order by ltv.termApplicableFrom
|
||||||
|
""")
|
||||||
|
List<LoanTermVariationsData> findLoanTermVariationsByLoanIdAndTermType(@Param("loanId") long loanId, @Param("termType") int termType);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -20,7 +20,6 @@ package org.apache.fineract.infrastructure.event.external.service.serialization.
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.avro.generic.GenericContainer;
|
import org.apache.avro.generic.GenericContainer;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
@@ -86,9 +85,10 @@ public class LoanBusinessEventSerializer implements BusinessEventSerializer {
|
|||||||
List<LoanInstallmentDelinquencyBucketDataV1> installmentsDelinquencyData = installmentLevelDelinquencyEventProducer
|
List<LoanInstallmentDelinquencyBucketDataV1> installmentsDelinquencyData = installmentLevelDelinquencyEventProducer
|
||||||
.calculateInstallmentLevelDelinquencyData(event.get(), data.getCurrency());
|
.calculateInstallmentLevelDelinquencyData(event.get(), data.getCurrency());
|
||||||
|
|
||||||
Set<LoanTermVariations> activeLoanTermVariations = event.get().getActiveLoanTermVariations();
|
List<LoanTermVariations> activeLoanTermVariations = event.get().getActiveLoanTermVariations();
|
||||||
if (activeLoanTermVariations != null) {
|
|
||||||
data.setEmiAmountVariations(activeLoanTermVariations.stream().map(LoanTermVariations::toData).toList());
|
if (!activeLoanTermVariations.isEmpty()) {
|
||||||
|
data.setLoanTermVariations(activeLoanTermVariations.stream().map(LoanTermVariations::toData).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
LoanAccountDataV1 result = mapper.map(data);
|
LoanAccountDataV1 result = mapper.map(data);
|
||||||
|
|||||||
+1
-1
@@ -123,7 +123,7 @@ public class JobExecutionRepository {
|
|||||||
|
|
||||||
public Long getNotCompletedPartitionsCount(Long jobExecutionId, String partitionerStepName) {
|
public Long getNotCompletedPartitionsCount(Long jobExecutionId, String partitionerStepName) {
|
||||||
return namedParameterJdbcTemplate.queryForObject("""
|
return namedParameterJdbcTemplate.queryForObject("""
|
||||||
SELECT COUNT(bse.STEP_EXECUTION_ID)
|
SELECT COUNT(BSE.STEP_EXECUTION_ID)
|
||||||
FROM BATCH_STEP_EXECUTION BSE
|
FROM BATCH_STEP_EXECUTION BSE
|
||||||
WHERE
|
WHERE
|
||||||
BSE.JOB_EXECUTION_ID = :jobExecutionId
|
BSE.JOB_EXECUTION_ID = :jobExecutionId
|
||||||
|
|||||||
+14
-4
@@ -146,6 +146,7 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanSchedul
|
|||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleCalculationPlatformService;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleCalculationPlatformService;
|
||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryReadPlatformService;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryReadPlatformService;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanTermVariationsRepository;
|
||||||
import org.apache.fineract.portfolio.loanaccount.service.GLIMAccountInfoReadPlatformService;
|
import org.apache.fineract.portfolio.loanaccount.service.GLIMAccountInfoReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.loanaccount.service.LoanChargeReadPlatformService;
|
import org.apache.fineract.portfolio.loanaccount.service.LoanChargeReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||||
@@ -287,6 +288,7 @@ public class LoansApiResource {
|
|||||||
private final SqlValidator sqlValidator;
|
private final SqlValidator sqlValidator;
|
||||||
private final LoanSummaryBalancesRepository loanSummaryBalancesRepository;
|
private final LoanSummaryBalancesRepository loanSummaryBalancesRepository;
|
||||||
private final ClientReadPlatformService clientReadPlatformService;
|
private final ClientReadPlatformService clientReadPlatformService;
|
||||||
|
private final LoanTermVariationsRepository loanTermVariationsRepository;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This template API is used for loan approval, ideally this should be invoked on loan that are pending for
|
* This template API is used for loan approval, ideally this should be invoked on loan that are pending for
|
||||||
@@ -897,7 +899,8 @@ public class LoansApiResource {
|
|||||||
Collection<NoteData> notes = null;
|
Collection<NoteData> notes = null;
|
||||||
PortfolioAccountData linkedAccount = null;
|
PortfolioAccountData linkedAccount = null;
|
||||||
Collection<DisbursementData> disbursementData = null;
|
Collection<DisbursementData> disbursementData = null;
|
||||||
Collection<LoanTermVariationsData> emiAmountVariations = null;
|
List<LoanTermVariationsData> emiAmountVariations = null;
|
||||||
|
List<LoanTermVariationsData> loanTermVariations = null;
|
||||||
Collection<LoanCollateralResponseData> loanCollateralManagements;
|
Collection<LoanCollateralResponseData> loanCollateralManagements;
|
||||||
Collection<LoanCollateralManagementData> loanCollateralManagementData = new ArrayList<>();
|
Collection<LoanCollateralManagementData> loanCollateralManagementData = new ArrayList<>();
|
||||||
CollectionData collectionData = this.delinquencyReadPlatformService.calculateLoanCollectionData(resolvedLoanId);
|
CollectionData collectionData = this.delinquencyReadPlatformService.calculateLoanCollectionData(resolvedLoanId);
|
||||||
@@ -911,7 +914,8 @@ public class LoansApiResource {
|
|||||||
DataTableApiConstant.transactionsAssociateParamName, DataTableApiConstant.chargesAssociateParamName,
|
DataTableApiConstant.transactionsAssociateParamName, DataTableApiConstant.chargesAssociateParamName,
|
||||||
DataTableApiConstant.guarantorsAssociateParamName, DataTableApiConstant.collateralAssociateParamName,
|
DataTableApiConstant.guarantorsAssociateParamName, DataTableApiConstant.collateralAssociateParamName,
|
||||||
DataTableApiConstant.notesAssociateParamName, DataTableApiConstant.linkedAccountAssociateParamName,
|
DataTableApiConstant.notesAssociateParamName, DataTableApiConstant.linkedAccountAssociateParamName,
|
||||||
DataTableApiConstant.multiDisburseDetailsAssociateParamName, DataTableApiConstant.collectionAssociateParamName));
|
DataTableApiConstant.multiDisburseDetailsAssociateParamName, DataTableApiConstant.collectionAssociateParamName,
|
||||||
|
DataTableApiConstant.loanTermVariationsAssociateParamName));
|
||||||
}
|
}
|
||||||
|
|
||||||
ApiParameterHelper.excludeAssociationsForResponseIfProvided(exclude, associationParameters);
|
ApiParameterHelper.excludeAssociationsForResponseIfProvided(exclude, associationParameters);
|
||||||
@@ -938,10 +942,15 @@ public class LoansApiResource {
|
|||||||
if (associationParameters.contains(DataTableApiConstant.emiAmountVariationsAssociateParamName)
|
if (associationParameters.contains(DataTableApiConstant.emiAmountVariationsAssociateParamName)
|
||||||
|| associationParameters.contains(DataTableApiConstant.repaymentScheduleAssociateParamName)) {
|
|| associationParameters.contains(DataTableApiConstant.repaymentScheduleAssociateParamName)) {
|
||||||
mandatoryResponseParameters.add(DataTableApiConstant.emiAmountVariationsAssociateParamName);
|
mandatoryResponseParameters.add(DataTableApiConstant.emiAmountVariationsAssociateParamName);
|
||||||
emiAmountVariations = this.loanReadPlatformService.retrieveLoanTermVariations(resolvedLoanId,
|
emiAmountVariations = this.loanTermVariationsRepository.findLoanTermVariationsByLoanIdAndTermType(resolvedLoanId,
|
||||||
LoanTermVariationType.EMI_AMOUNT.getValue());
|
LoanTermVariationType.EMI_AMOUNT.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (associationParameters.contains(DataTableApiConstant.loanTermVariationsAssociateParamName)) {
|
||||||
|
mandatoryResponseParameters.add(DataTableApiConstant.loanTermVariationsAssociateParamName);
|
||||||
|
loanTermVariations = this.loanTermVariationsRepository.findLoanTermVariationsByLoanId(resolvedLoanId);
|
||||||
|
}
|
||||||
|
|
||||||
if (associationParameters.contains(DataTableApiConstant.repaymentScheduleAssociateParamName)) {
|
if (associationParameters.contains(DataTableApiConstant.repaymentScheduleAssociateParamName)) {
|
||||||
mandatoryResponseParameters.add(DataTableApiConstant.repaymentScheduleAssociateParamName);
|
mandatoryResponseParameters.add(DataTableApiConstant.repaymentScheduleAssociateParamName);
|
||||||
final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData = new RepaymentScheduleRelatedLoanData(
|
final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData = new RepaymentScheduleRelatedLoanData(
|
||||||
@@ -1118,7 +1127,8 @@ public class LoansApiResource {
|
|||||||
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, loanPurposeOptions,
|
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, loanPurposeOptions,
|
||||||
loanCollateralOptions, calendarOptions, notes, accountLinkingOptions, linkedAccount, disbursementData, emiAmountVariations,
|
loanCollateralOptions, calendarOptions, notes, accountLinkingOptions, linkedAccount, disbursementData, emiAmountVariations,
|
||||||
overdueCharges, paidInAdvanceTemplate, interestRatesPeriods, clientActiveLoanOptions, rates, isRatesEnabled, collectionData,
|
overdueCharges, paidInAdvanceTemplate, interestRatesPeriods, clientActiveLoanOptions, rates, isRatesEnabled, collectionData,
|
||||||
LoanScheduleType.getValuesAsEnumOptionDataList(), LoanScheduleProcessingType.getValuesAsEnumOptionDataList());
|
LoanScheduleType.getValuesAsEnumOptionDataList(), LoanScheduleProcessingType.getValuesAsEnumOptionDataList(),
|
||||||
|
loanTermVariations);
|
||||||
|
|
||||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters(),
|
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters(),
|
||||||
mandatoryResponseParameters);
|
mandatoryResponseParameters);
|
||||||
|
|||||||
+42
-6
@@ -432,11 +432,6 @@ final class LoansApiResourceSwagger {
|
|||||||
|
|
||||||
private GetLoansLoanIdSummary() {}
|
private GetLoansLoanIdSummary() {}
|
||||||
|
|
||||||
static final class GetLoansLoanIdEmiVariations {
|
|
||||||
|
|
||||||
private GetLoansLoanIdEmiVariations() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
static final class GetLoansLoanIdLinkedAccount {
|
static final class GetLoansLoanIdLinkedAccount {
|
||||||
|
|
||||||
private GetLoansLoanIdLinkedAccount() {}
|
private GetLoansLoanIdLinkedAccount() {}
|
||||||
@@ -606,7 +601,6 @@ final class LoansApiResourceSwagger {
|
|||||||
public Double maxOutstandingLoanBalance;
|
public Double maxOutstandingLoanBalance;
|
||||||
@Schema(example = "false")
|
@Schema(example = "false")
|
||||||
public Boolean canDisburse;
|
public Boolean canDisburse;
|
||||||
public Set<GetLoansLoanIdEmiVariations> emiAmountVariations;
|
|
||||||
@Schema(example = "true")
|
@Schema(example = "true")
|
||||||
public Boolean inArrears;
|
public Boolean inArrears;
|
||||||
@Schema(example = "false")
|
@Schema(example = "false")
|
||||||
@@ -1072,6 +1066,38 @@ final class LoansApiResourceSwagger {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static final class GetLoansLoanIdLoanTermVariations {
|
||||||
|
|
||||||
|
private GetLoansLoanIdLoanTermVariations() {}
|
||||||
|
|
||||||
|
static final class GetLoansLoanIdLoanTermEnumData {
|
||||||
|
|
||||||
|
private GetLoansLoanIdLoanTermEnumData() {}
|
||||||
|
|
||||||
|
@Schema(example = "1")
|
||||||
|
public Long id;
|
||||||
|
@Schema(example = "loanTermType.emiAmount")
|
||||||
|
public String code;
|
||||||
|
@Schema(example = "emiAmount")
|
||||||
|
public String value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Schema(example = "1")
|
||||||
|
public Long id;
|
||||||
|
@Schema(description = "Enum option data")
|
||||||
|
public GetLoansLoanIdLoanTermEnumData termType;
|
||||||
|
@Schema(example = "[2024, 1, 1]")
|
||||||
|
public LocalDate termVariationApplicableFrom;
|
||||||
|
@Schema(example = "200.000000")
|
||||||
|
public Double decimalValue;
|
||||||
|
@Schema(example = "[2024, 1, 1]")
|
||||||
|
public LocalDate dateValue;
|
||||||
|
@Schema(example = "false")
|
||||||
|
public boolean isSpecificToInstallment;
|
||||||
|
@Schema(example = "false")
|
||||||
|
public boolean isProcessed;
|
||||||
|
}
|
||||||
|
|
||||||
@Schema(example = "1")
|
@Schema(example = "1")
|
||||||
public Long id;
|
public Long id;
|
||||||
@Schema(example = "95174ff9-1a75-4d72-a413-6f9b1cb988b7")
|
@Schema(example = "95174ff9-1a75-4d72-a413-6f9b1cb988b7")
|
||||||
@@ -1172,6 +1198,10 @@ final class LoansApiResourceSwagger {
|
|||||||
public EnumOptionData loanScheduleType;
|
public EnumOptionData loanScheduleType;
|
||||||
@Schema(example = "HORIZONTAL")
|
@Schema(example = "HORIZONTAL")
|
||||||
public EnumOptionData loanScheduleProcessingType;
|
public EnumOptionData loanScheduleProcessingType;
|
||||||
|
@Schema(description = "List of GetLoansLoanIdLoanTermVariations")
|
||||||
|
public List<GetLoansLoanIdLoanTermVariations> emiAmountVariations;
|
||||||
|
@Schema(description = "List of GetLoansLoanIdLoanTermVariations")
|
||||||
|
public List<GetLoansLoanIdLoanTermVariations> loanTermVariations;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Schema(description = "GetLoansResponse")
|
@Schema(description = "GetLoansResponse")
|
||||||
@@ -1267,6 +1297,8 @@ final class LoansApiResourceSwagger {
|
|||||||
public BigDecimal disbursedAmountPercentageForDownPayment;
|
public BigDecimal disbursedAmountPercentageForDownPayment;
|
||||||
@Schema(example = "false")
|
@Schema(example = "false")
|
||||||
public Boolean enableAutoRepaymentForDownPayment;
|
public Boolean enableAutoRepaymentForDownPayment;
|
||||||
|
@Schema(example = "10.00")
|
||||||
|
public BigDecimal fixedEmiAmount;
|
||||||
|
|
||||||
public List<PostLoansRequestChargeData> charges;
|
public List<PostLoansRequestChargeData> charges;
|
||||||
|
|
||||||
@@ -1588,6 +1620,10 @@ final class LoansApiResourceSwagger {
|
|||||||
public String withdrawnOnDate;
|
public String withdrawnOnDate;
|
||||||
@Schema(description = "List of PostLoansLoanIdDisbursementData")
|
@Schema(description = "List of PostLoansLoanIdDisbursementData")
|
||||||
public List<PostLoansLoanIdDisbursementData> disbursementData;
|
public List<PostLoansLoanIdDisbursementData> disbursementData;
|
||||||
|
@Schema(example = "500.00")
|
||||||
|
public BigDecimal fixedEmiAmount;
|
||||||
|
@Schema(example = "28 July 2022")
|
||||||
|
public String adjustRepaymentDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Schema(description = "PostLoansLoanIdResponse")
|
@Schema(description = "PostLoansLoanIdResponse")
|
||||||
|
|||||||
+3
-2
@@ -194,6 +194,7 @@ public class LoanAccountData {
|
|||||||
private Boolean canDisburse;
|
private Boolean canDisburse;
|
||||||
|
|
||||||
private Collection<LoanTermVariationsData> emiAmountVariations;
|
private Collection<LoanTermVariationsData> emiAmountVariations;
|
||||||
|
private Collection<LoanTermVariationsData> loanTermVariations;
|
||||||
private Collection<LoanAccountSummaryData> clientActiveLoanOptions;
|
private Collection<LoanAccountSummaryData> clientActiveLoanOptions;
|
||||||
private Boolean canUseForTopup;
|
private Boolean canUseForTopup;
|
||||||
// TODO: avoid prefix "is"
|
// TODO: avoid prefix "is"
|
||||||
@@ -521,7 +522,7 @@ public class LoanAccountData {
|
|||||||
final PaidInAdvanceData paidInAdvance, Collection<InterestRatePeriodData> interestRatesPeriods,
|
final PaidInAdvanceData paidInAdvance, Collection<InterestRatePeriodData> interestRatesPeriods,
|
||||||
final Collection<LoanAccountSummaryData> clientActiveLoanOptions, final List<RateData> rates, final Boolean isRatesEnabled,
|
final Collection<LoanAccountSummaryData> clientActiveLoanOptions, final List<RateData> rates, final Boolean isRatesEnabled,
|
||||||
final CollectionData delinquent, final List<EnumOptionData> loanScheduleTypeOptions,
|
final CollectionData delinquent, final List<EnumOptionData> loanScheduleTypeOptions,
|
||||||
final List<EnumOptionData> loanScheduleProcessingTypeOptions) {
|
final List<EnumOptionData> loanScheduleProcessingTypeOptions, final List<LoanTermVariationsData> loanTermVariations) {
|
||||||
|
|
||||||
// TODO: why are these variables 'calendarData', 'chargeTemplate' never used (see original private constructor)
|
// TODO: why are these variables 'calendarData', 'chargeTemplate' never used (see original private constructor)
|
||||||
|
|
||||||
@@ -541,7 +542,7 @@ public class LoanAccountData {
|
|||||||
.setOverdueCharges(overdueCharges).setPaidInAdvance(paidInAdvance).setInterestRatesPeriods(interestRatesPeriods)
|
.setOverdueCharges(overdueCharges).setPaidInAdvance(paidInAdvance).setInterestRatesPeriods(interestRatesPeriods)
|
||||||
.setClientActiveLoanOptions(clientActiveLoanOptions).setRates(rates).setIsRatesEnabled(isRatesEnabled)
|
.setClientActiveLoanOptions(clientActiveLoanOptions).setRates(rates).setIsRatesEnabled(isRatesEnabled)
|
||||||
.setDelinquent(delinquent).setLoanScheduleTypeOptions(loanScheduleTypeOptions)
|
.setDelinquent(delinquent).setLoanScheduleTypeOptions(loanScheduleTypeOptions)
|
||||||
.setLoanScheduleProcessingTypeOptions(loanScheduleProcessingTypeOptions);
|
.setLoanScheduleProcessingTypeOptions(loanScheduleProcessingTypeOptions).setLoanTermVariations(loanTermVariations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoanAccountData associationsAndTemplate(final Collection<LoanProductData> productOptions,
|
public LoanAccountData associationsAndTemplate(final Collection<LoanProductData> productOptions,
|
||||||
|
|||||||
+2
-2
@@ -370,9 +370,9 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
|||||||
final LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(scheduleGeneratorDTO);
|
final LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(scheduleGeneratorDTO);
|
||||||
|
|
||||||
LocalDate rescheduleFromDate = null;
|
LocalDate rescheduleFromDate = null;
|
||||||
Set<LoanTermVariations> activeLoanTermVariations = loan.getActiveLoanTermVariations();
|
List<LoanTermVariations> activeLoanTermVariations = loan.getActiveLoanTermVariations();
|
||||||
LoanTermVariations dueDateVariationInCurrentRequest = loanRescheduleRequest.getDueDateTermVariationIfExists();
|
LoanTermVariations dueDateVariationInCurrentRequest = loanRescheduleRequest.getDueDateTermVariationIfExists();
|
||||||
if (dueDateVariationInCurrentRequest != null && activeLoanTermVariations != null) {
|
if (dueDateVariationInCurrentRequest != null && !activeLoanTermVariations.isEmpty()) {
|
||||||
LocalDate fromScheduleDate = dueDateVariationInCurrentRequest.fetchTermApplicaDate();
|
LocalDate fromScheduleDate = dueDateVariationInCurrentRequest.fetchTermApplicaDate();
|
||||||
LocalDate currentScheduleDate = fromScheduleDate;
|
LocalDate currentScheduleDate = fromScheduleDate;
|
||||||
LocalDate modifiedScheduleDate = dueDateVariationInCurrentRequest.fetchDateValue();
|
LocalDate modifiedScheduleDate = dueDateVariationInCurrentRequest.fetchDateValue();
|
||||||
|
|||||||
-3
@@ -32,7 +32,6 @@ import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData;
|
|||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanApprovalData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanApprovalData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanRepaymentScheduleInstallmentData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanRepaymentScheduleInstallmentData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleAccrualData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleAccrualData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.PaidInAdvanceData;
|
import org.apache.fineract.portfolio.loanaccount.data.PaidInAdvanceData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
|
import org.apache.fineract.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
|
||||||
@@ -99,8 +98,6 @@ public interface LoanReadPlatformService {
|
|||||||
|
|
||||||
DisbursementData retrieveLoanDisbursementDetail(Long loanId, Long disbursementId);
|
DisbursementData retrieveLoanDisbursementDetail(Long loanId, Long disbursementId);
|
||||||
|
|
||||||
Collection<LoanTermVariationsData> retrieveLoanTermVariations(Long loanId, Integer termType);
|
|
||||||
|
|
||||||
Collection<LoanScheduleAccrualData> retriveScheduleAccrualData();
|
Collection<LoanScheduleAccrualData> retriveScheduleAccrualData();
|
||||||
|
|
||||||
LoanTransactionData retrieveRecoveryPaymentTemplate(Long loanId);
|
LoanTransactionData retrieveRecoveryPaymentTemplate(Long loanId);
|
||||||
|
|||||||
-29
@@ -100,7 +100,6 @@ import org.apache.fineract.portfolio.loanaccount.data.LoanRepaymentScheduleInsta
|
|||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleAccrualData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleAccrualData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanStatusEnumData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanStatusEnumData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanSummaryData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanSummaryData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionEnumData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionEnumData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionRelationData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionRelationData;
|
||||||
@@ -114,7 +113,6 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTra
|
|||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanSubStatus;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanSubStatus;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
|
||||||
@@ -1740,33 +1738,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
|
|||||||
return this.jdbcTemplate.queryForObject(sql, rm, loanId, disbursementId); // NOSONAR
|
return this.jdbcTemplate.queryForObject(sql, rm, loanId, disbursementId); // NOSONAR
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<LoanTermVariationsData> retrieveLoanTermVariations(Long loanId, Integer termType) {
|
|
||||||
final LoanTermVariationsMapper rm = new LoanTermVariationsMapper();
|
|
||||||
final String sql = "select " + rm.schema() + " where tv.loan_id=? and tv.term_type=?";
|
|
||||||
return this.jdbcTemplate.query(sql, rm, loanId, termType); // NOSONAR
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class LoanTermVariationsMapper implements RowMapper<LoanTermVariationsData> {
|
|
||||||
|
|
||||||
public String schema() {
|
|
||||||
return "tv.id as id,tv.applicable_date as variationApplicableFrom,tv.decimal_value as decimalValue, tv.date_value as dateValue, tv.is_specific_to_installment as isSpecificToInstallment "
|
|
||||||
+ "from m_loan_term_variations tv";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LoanTermVariationsData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
|
||||||
final Long id = rs.getLong("id");
|
|
||||||
final LocalDate variationApplicableFrom = JdbcSupport.getLocalDate(rs, "variationApplicableFrom");
|
|
||||||
final BigDecimal decimalValue = rs.getBigDecimal("decimalValue");
|
|
||||||
final LocalDate dateValue = JdbcSupport.getLocalDate(rs, "dateValue");
|
|
||||||
final boolean isSpecificToInstallment = rs.getBoolean("isSpecificToInstallment");
|
|
||||||
|
|
||||||
return new LoanTermVariationsData(id, LoanEnumerations.loanVariationType(LoanTermVariationType.EMI_AMOUNT),
|
|
||||||
variationApplicableFrom, decimalValue, dateValue, isSpecificToInstallment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<LoanScheduleAccrualData> retriveScheduleAccrualData() {
|
public Collection<LoanScheduleAccrualData> retriveScheduleAccrualData() {
|
||||||
final String chargeAccrualDateCriteria = configurationDomainService.getAccrualDateConfigForCharge();
|
final String chargeAccrualDateCriteria = configurationDomainService.getAccrualDateConfigForCharge();
|
||||||
|
|||||||
+3
@@ -94,6 +94,7 @@ import org.apache.fineract.infrastructure.core.service.DateUtils;
|
|||||||
import org.apache.fineract.integrationtests.common.BusinessDateHelper;
|
import org.apache.fineract.integrationtests.common.BusinessDateHelper;
|
||||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||||
import org.apache.fineract.integrationtests.common.CollateralManagementHelper;
|
import org.apache.fineract.integrationtests.common.CollateralManagementHelper;
|
||||||
|
import org.apache.fineract.integrationtests.common.LoanRescheduleRequestHelper;
|
||||||
import org.apache.fineract.integrationtests.common.SchedulerJobHelper;
|
import org.apache.fineract.integrationtests.common.SchedulerJobHelper;
|
||||||
import org.apache.fineract.integrationtests.common.Utils;
|
import org.apache.fineract.integrationtests.common.Utils;
|
||||||
import org.apache.fineract.integrationtests.common.accounting.Account;
|
import org.apache.fineract.integrationtests.common.accounting.Account;
|
||||||
@@ -176,6 +177,8 @@ public class ClientLoanIntegrationTest extends BaseLoanIntegrationTest {
|
|||||||
private static final BusinessDateHelper BUSINESS_DATE_HELPER = new BusinessDateHelper();
|
private static final BusinessDateHelper BUSINESS_DATE_HELPER = new BusinessDateHelper();
|
||||||
private static final ChargesHelper CHARGES_HELPER = new ChargesHelper();
|
private static final ChargesHelper CHARGES_HELPER = new ChargesHelper();
|
||||||
private static final ClientHelper CLIENT_HELPER = new ClientHelper(REQUEST_SPEC, RESPONSE_SPEC);
|
private static final ClientHelper CLIENT_HELPER = new ClientHelper(REQUEST_SPEC, RESPONSE_SPEC);
|
||||||
|
private static final LoanRescheduleRequestHelper LOAN_RESCHEDULE_REQUEST_HELPER = new LoanRescheduleRequestHelper(REQUEST_SPEC,
|
||||||
|
RESPONSE_SPEC);
|
||||||
|
|
||||||
private static RequestSpecification createRequestSpecification() {
|
private static RequestSpecification createRequestSpecification() {
|
||||||
RequestSpecification request = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
|
RequestSpecification request = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
|
||||||
|
|||||||
+10
-17
@@ -290,30 +290,23 @@ public class ExternalBusinessEventTest extends BaseLoanIntegrationTest {
|
|||||||
&& Objects.equals(statusId, businessEvent.getStatusId().doubleValue())
|
&& Objects.equals(statusId, businessEvent.getStatusId().doubleValue())
|
||||||
&& Objects.equals(principalDisbursed, businessEvent.getPrincipalDisbursed())
|
&& Objects.equals(principalDisbursed, businessEvent.getPrincipalDisbursed())
|
||||||
&& Objects.equals(principalOutstanding, businessEvent.getPrincipalOutstanding())
|
&& Objects.equals(principalOutstanding, businessEvent.getPrincipalOutstanding())
|
||||||
&& emiAmountVariationsMatch((List<Map<String, Object>>) externalEvent.getPayLoad().get("emiAmountVariations"),
|
&& loanTermVariationsMatch((List<Map<String, Object>>) externalEvent.getPayLoad().get("loanTermVariations"),
|
||||||
businessEvent.emiAmountVariationType);
|
businessEvent.loanTermVariationType);
|
||||||
}).count();
|
}).count();
|
||||||
Assertions.assertEquals(1, count, "Expected business event not found " + businessEvent);
|
Assertions.assertEquals(1, count, "Expected business event not found " + businessEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean emiAmountVariationsMatch(List<Map<String, Object>> emiAmountVariations, List<String> expectedTypes) {
|
private boolean loanTermVariationsMatch(final List<Map<String, Object>> loanTermVariations, final List<String> expectedTypes) {
|
||||||
if (CollectionUtils.isEmpty(expectedTypes)) {
|
if (CollectionUtils.isEmpty(expectedTypes)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
int numberOfMatches = 0;
|
final long numberOfMatches = expectedTypes
|
||||||
if (CollectionUtils.isNotEmpty(emiAmountVariations)) {
|
.stream().filter(
|
||||||
for (String expectedType : expectedTypes) {
|
expectedType -> loanTermVariations.stream()
|
||||||
int i = 0;
|
.anyMatch(variation -> StringUtils
|
||||||
while (i < emiAmountVariations.size() && !StringUtils
|
.equals((String) ((Map<String, Object>) variation.get("termType")).get("value"), expectedType)))
|
||||||
.equals((String) ((Map<String, Object>) emiAmountVariations.get(i).get("termType")).get("value"), expectedType)) {
|
.count();
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if (i < emiAmountVariations.size()) {
|
|
||||||
numberOfMatches++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return numberOfMatches == expectedTypes.size();
|
return numberOfMatches == expectedTypes.size();
|
||||||
}
|
}
|
||||||
@@ -335,6 +328,6 @@ public class ExternalBusinessEventTest extends BaseLoanIntegrationTest {
|
|||||||
private Integer statusId;
|
private Integer statusId;
|
||||||
private Double principalDisbursed;
|
private Double principalDisbursed;
|
||||||
private Double principalOutstanding;
|
private Double principalOutstanding;
|
||||||
private List<String> emiAmountVariationType;
|
private List<String> loanTermVariationType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user