FINERACT-2380: create feign client
This commit is contained in:
+65
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.client;
|
||||
|
||||
import org.apache.fineract.client.feign.FineractFeignClient;
|
||||
import org.apache.fineract.client.feign.FineractFeignClientConfig;
|
||||
import org.apache.fineract.integrationtests.ConfigProperties;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Simple smoke tests for Feign-based Fineract client
|
||||
*
|
||||
*/
|
||||
public class FeignClientSmokeTest extends FeignIntegrationTest {
|
||||
|
||||
private String getTestUrl() {
|
||||
return System.getProperty("fineract.it.url", ConfigProperties.Backend.PROTOCOL + "://" + ConfigProperties.Backend.HOST + ":"
|
||||
+ ConfigProperties.Backend.PORT + "/fineract-provider/api");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
public void testFeignClientBuilder() {
|
||||
FineractFeignClient.Builder builder = FineractFeignClient.builder().baseUrl(getTestUrl())
|
||||
.credentials(ConfigProperties.Backend.USERNAME, ConfigProperties.Backend.PASSWORD);
|
||||
|
||||
assertThat(builder).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void testFeignClientConfig() {
|
||||
FineractFeignClientConfig.Builder configBuilder = FineractFeignClientConfig.builder().baseUrl(getTestUrl())
|
||||
.credentials(ConfigProperties.Backend.USERNAME, ConfigProperties.Backend.PASSWORD).debugEnabled(true);
|
||||
|
||||
FineractFeignClientConfig config = configBuilder.build();
|
||||
|
||||
assertThat(config).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
public void testFeignClientCanInstantiateApis() {
|
||||
assertThat(fineractClient()).isNotNull();
|
||||
assertThat(fineractClient().offices()).isNotNull();
|
||||
assertThat(fineractClient().clients()).isNotNull();
|
||||
}
|
||||
}
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.client;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import feign.Response;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import org.apache.fineract.client.feign.FeignException;
|
||||
import org.apache.fineract.client.feign.FineractMultipartEncoder;
|
||||
import org.apache.fineract.client.models.DocumentData;
|
||||
import org.apache.fineract.client.models.PostEntityTypeEntityIdDocumentsResponse;
|
||||
import org.apache.fineract.integrationtests.client.feign.helpers.FeignClientHelper;
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public class FeignDocumentTest extends FeignIntegrationTest {
|
||||
|
||||
final File testFile = new File(getClass().getResource("/michael.vorburger-crepes.jpg").getFile());
|
||||
|
||||
Long clientId;
|
||||
Long documentId;
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
void setupClient() {
|
||||
FeignClientHelper clientHelper = new FeignClientHelper(fineractClient());
|
||||
clientId = clientHelper.createClient("Feign", "Test");
|
||||
assertThat(clientId).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
void testCreateDocument() throws IOException {
|
||||
String name = "Feign Test Document";
|
||||
String description = "Testing DocumentsApiFixed with Feign client";
|
||||
|
||||
byte[] fileData = Files.readAllBytes(testFile.toPath());
|
||||
FineractMultipartEncoder.MultipartData multipartData = new FineractMultipartEncoder.MultipartData()
|
||||
.addFile("file", testFile.getName(), fileData, "image/jpeg").addText("name", name).addText("description", description);
|
||||
|
||||
PostEntityTypeEntityIdDocumentsResponse response = ok(
|
||||
() -> fineractClient().documentsFixed().createDocument("clients", clientId, multipartData));
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.getResourceId()).isNotNull();
|
||||
documentId = response.getResourceId();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
void testRetrieveAllDocuments() {
|
||||
var documents = ok(() -> fineractClient().documentsFixed().retrieveAllDocuments("clients", clientId));
|
||||
|
||||
assertThat(documents).isNotNull();
|
||||
assertThat(documents).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
void testGetDocument() {
|
||||
DocumentData doc = ok(() -> fineractClient().documentsFixed().getDocument("clients", clientId, documentId));
|
||||
|
||||
assertThat(doc).isNotNull();
|
||||
assertThat(doc.getName()).isEqualTo("Feign Test Document");
|
||||
assertThat(doc.getFileName()).isEqualTo(testFile.getName());
|
||||
assertThat(doc.getDescription()).isEqualTo("Testing DocumentsApiFixed with Feign client");
|
||||
assertThat(doc.getId()).isEqualTo(documentId);
|
||||
assertThat(doc.getParentEntityType()).isEqualTo("clients");
|
||||
assertThat(doc.getParentEntityId()).isEqualTo(clientId);
|
||||
assertThat(doc.getType()).isEqualTo("image/jpeg");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(5)
|
||||
void testDownloadFile() throws IOException {
|
||||
Response response = fineractClient().documentsFixed().downloadFile("clients", clientId, documentId);
|
||||
|
||||
assertNotNull(response);
|
||||
assertEquals(200, response.status());
|
||||
|
||||
try (InputStream inputStream = response.body().asInputStream()) {
|
||||
byte[] bytes = inputStream.readAllBytes();
|
||||
assertThat(bytes.length).isEqualTo((int) testFile.length());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(6)
|
||||
void testUpdateDocument() {
|
||||
String newName = "Updated Feign Test";
|
||||
String newDescription = "Updated via Feign client";
|
||||
|
||||
FineractMultipartEncoder.MultipartData multipartData = new FineractMultipartEncoder.MultipartData().addText("name", newName)
|
||||
.addText("description", newDescription);
|
||||
|
||||
var updateResponse = ok(() -> fineractClient().documentsFixed().updateDocument("clients", clientId, documentId, multipartData));
|
||||
|
||||
assertThat(updateResponse).isNotNull();
|
||||
|
||||
DocumentData doc = ok(() -> fineractClient().documentsFixed().getDocument("clients", clientId, documentId));
|
||||
assertThat(doc.getName()).isEqualTo(newName);
|
||||
assertThat(doc.getDescription()).isEqualTo(newDescription);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(99)
|
||||
void testDeleteDocument() {
|
||||
var deleteResponse = ok(() -> fineractClient().documentsFixed().deleteDocument("clients", clientId, documentId));
|
||||
assertThat(deleteResponse).isNotNull();
|
||||
|
||||
FeignException exception = assertThrows(FeignException.class,
|
||||
() -> fineractClient().documentsFixed().getDocument("clients", clientId, documentId));
|
||||
assertEquals(404, exception.status());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(9999)
|
||||
void testCreateDocumentBadArgs() {
|
||||
FineractMultipartEncoder.MultipartData multipartData = new FineractMultipartEncoder.MultipartData().addText("name", "test.pdf");
|
||||
|
||||
FeignException exception = assertThrows(FeignException.class,
|
||||
() -> fineractClient().documentsFixed().createDocument("clients", clientId, multipartData));
|
||||
assertEquals(400, exception.status());
|
||||
}
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.client;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import feign.Response;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.HashMap;
|
||||
import org.apache.fineract.client.feign.FineractFeignClient;
|
||||
import org.apache.fineract.client.models.CreateStaffResponse;
|
||||
import org.apache.fineract.client.models.StaffRequest;
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public class FeignImageTest extends FeignIntegrationTest {
|
||||
|
||||
final File testImage = new File(getClass().getResource("/michael.vorburger-crepes.jpg").getFile());
|
||||
|
||||
Long staffId;
|
||||
|
||||
@Override
|
||||
protected FineractFeignClient fineractClient() {
|
||||
return org.apache.fineract.integrationtests.common.FineractFeignClientHelper.createNewFineractFeignClient("mifos", "password",
|
||||
true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
void setupStaff() {
|
||||
StaffRequest request = new StaffRequest();
|
||||
request.setOfficeId(1L);
|
||||
request.setFirstname("Feign");
|
||||
request.setLastname("ImageTest" + System.currentTimeMillis());
|
||||
request.setJoiningDate(LocalDate.now(ZoneId.of("UTC")).toString());
|
||||
request.setDateFormat("yyyy-MM-dd");
|
||||
request.setLocale("en_US");
|
||||
|
||||
CreateStaffResponse response = ok(() -> fineractClient().staff().create3(request));
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.getResourceId()).isNotNull();
|
||||
staffId = response.getResourceId();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
void testCreateStaffImage() throws Exception {
|
||||
String dataUrl = org.apache.fineract.client.feign.services.ImagesApi.prepareFileUpload(testImage);
|
||||
Response response = fineractClient().images().create("staff", staffId, dataUrl);
|
||||
|
||||
assertNotNull(response);
|
||||
assertEquals(200, response.status());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
void testRetrieveStaffImage() throws IOException {
|
||||
Response response = fineractClient().images().get("staff", staffId, new HashMap<>());
|
||||
|
||||
assertNotNull(response);
|
||||
assertEquals(200, response.status());
|
||||
|
||||
try (InputStream inputStream = response.body().asInputStream()) {
|
||||
byte[] bytes = inputStream.readAllBytes();
|
||||
assertThat(bytes.length).isGreaterThan(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
void testUpdateStaffImage() {
|
||||
Response response = fineractClient().images().update("staff", staffId,
|
||||
org.apache.fineract.client.feign.services.ImagesApi.prepareFileUpload(testImage));
|
||||
|
||||
assertNotNull(response);
|
||||
assertEquals(200, response.status());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(99)
|
||||
void testDeleteStaffImage() {
|
||||
Response response = fineractClient().images().delete("staff", staffId);
|
||||
|
||||
assertNotNull(response);
|
||||
assertEquals(200, response.status());
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.client;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import org.apache.fineract.client.feign.FineractFeignClient;
|
||||
import org.apache.fineract.client.feign.util.FeignCalls;
|
||||
import org.apache.fineract.integrationtests.common.FineractFeignClientHelper;
|
||||
import org.assertj.core.api.AbstractBigDecimalAssert;
|
||||
import org.assertj.core.api.AbstractBooleanAssert;
|
||||
import org.assertj.core.api.AbstractDoubleAssert;
|
||||
import org.assertj.core.api.AbstractFloatAssert;
|
||||
import org.assertj.core.api.AbstractIntegerAssert;
|
||||
import org.assertj.core.api.AbstractLongAssert;
|
||||
import org.assertj.core.api.AbstractStringAssert;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.assertj.core.api.IterableAssert;
|
||||
import org.assertj.core.api.ObjectAssert;
|
||||
import org.assertj.core.api.OptionalAssert;
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
import org.junit.jupiter.api.TestInstance;
|
||||
import org.junit.jupiter.api.TestInstance.Lifecycle;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
|
||||
/**
|
||||
* Base Integration Test class for Feign-based client
|
||||
*
|
||||
* @author Apache Fineract
|
||||
*/
|
||||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public abstract class FeignIntegrationTest {
|
||||
|
||||
protected FineractFeignClient fineractClient() {
|
||||
return FineractFeignClientHelper.getFineractFeignClient();
|
||||
}
|
||||
|
||||
protected <T> T ok(Supplier<T> call) {
|
||||
return FeignCalls.ok(call);
|
||||
}
|
||||
|
||||
protected void executeVoid(Runnable call) {
|
||||
FeignCalls.executeVoid(call);
|
||||
}
|
||||
|
||||
public static IterableAssert<?> assertThat(Iterable<?> actual) {
|
||||
return Assertions.assertThat(actual);
|
||||
}
|
||||
|
||||
public static AbstractBigDecimalAssert<?> assertThat(BigDecimal actual) {
|
||||
return Assertions.assertThat(actual);
|
||||
}
|
||||
|
||||
public static <T> ObjectAssert<T> assertThat(T actual) {
|
||||
return Assertions.assertThat(actual);
|
||||
}
|
||||
|
||||
public static AbstractLongAssert<?> assertThat(Long actual) {
|
||||
return Assertions.assertThat(actual);
|
||||
}
|
||||
|
||||
public static AbstractDoubleAssert<?> assertThat(Double actual) {
|
||||
return Assertions.assertThat(actual);
|
||||
}
|
||||
|
||||
public static AbstractFloatAssert<?> assertThat(Float actual) {
|
||||
return Assertions.assertThat(actual);
|
||||
}
|
||||
|
||||
public static AbstractIntegerAssert<?> assertThat(Integer actual) {
|
||||
return Assertions.assertThat(actual);
|
||||
}
|
||||
|
||||
public static AbstractBooleanAssert<?> assertThat(Boolean actual) {
|
||||
return Assertions.assertThat(actual);
|
||||
}
|
||||
|
||||
public static AbstractStringAssert<?> assertThat(String actual) {
|
||||
return Assertions.assertThat(actual);
|
||||
}
|
||||
|
||||
public static <T> OptionalAssert<T> assertThat(Optional<T> actual) {
|
||||
return Assertions.assertThat(actual);
|
||||
}
|
||||
}
|
||||
+219
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.client.feign;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.function.Function;
|
||||
import org.apache.fineract.client.feign.FineractFeignClient;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdStatus;
|
||||
import org.apache.fineract.client.models.PostLoanProductsRequest;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdRequest;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
|
||||
import org.apache.fineract.client.models.PostLoansRequest;
|
||||
import org.apache.fineract.integrationtests.client.FeignIntegrationTest;
|
||||
import org.apache.fineract.integrationtests.client.feign.helpers.FeignAccountHelper;
|
||||
import org.apache.fineract.integrationtests.client.feign.helpers.FeignBusinessDateHelper;
|
||||
import org.apache.fineract.integrationtests.client.feign.helpers.FeignClientHelper;
|
||||
import org.apache.fineract.integrationtests.client.feign.helpers.FeignJournalEntryHelper;
|
||||
import org.apache.fineract.integrationtests.client.feign.helpers.FeignLoanHelper;
|
||||
import org.apache.fineract.integrationtests.client.feign.helpers.FeignTransactionHelper;
|
||||
import org.apache.fineract.integrationtests.client.feign.modules.LoanProductTemplates;
|
||||
import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders;
|
||||
import org.apache.fineract.integrationtests.client.feign.modules.LoanTestAccounts;
|
||||
import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData;
|
||||
import org.apache.fineract.integrationtests.client.feign.modules.LoanTestValidators;
|
||||
import org.apache.fineract.integrationtests.common.FineractFeignClientHelper;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
public abstract class FeignLoanTestBase extends FeignIntegrationTest implements LoanProductTemplates {
|
||||
|
||||
protected static FeignAccountHelper accountHelper;
|
||||
protected static FeignLoanHelper loanHelper;
|
||||
protected static FeignTransactionHelper transactionHelper;
|
||||
protected static FeignJournalEntryHelper journalHelper;
|
||||
protected static FeignBusinessDateHelper businessDateHelper;
|
||||
protected static FeignClientHelper clientHelper;
|
||||
protected static LoanTestAccounts accounts;
|
||||
|
||||
@BeforeAll
|
||||
public static void setupHelpers() {
|
||||
FineractFeignClient client = FineractFeignClientHelper.getFineractFeignClient();
|
||||
accountHelper = new FeignAccountHelper(client);
|
||||
loanHelper = new FeignLoanHelper(client);
|
||||
transactionHelper = new FeignTransactionHelper(client);
|
||||
journalHelper = new FeignJournalEntryHelper(client);
|
||||
businessDateHelper = new FeignBusinessDateHelper(client);
|
||||
clientHelper = new FeignClientHelper(client);
|
||||
}
|
||||
|
||||
protected LoanTestAccounts getAccounts() {
|
||||
if (accounts == null) {
|
||||
accounts = new LoanTestAccounts(accountHelper);
|
||||
}
|
||||
return accounts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getAssetAccountId(String accountName) {
|
||||
return getAccounts().getAssetAccountId(accountName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLiabilityAccountId(String accountName) {
|
||||
return getAccounts().getLiabilityAccountId(accountName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getIncomeAccountId(String accountName) {
|
||||
return getAccounts().getIncomeAccountId(accountName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getExpenseAccountId(String accountName) {
|
||||
return getAccounts().getExpenseAccountId(accountName);
|
||||
}
|
||||
|
||||
protected Long createClient(String firstName, String lastName) {
|
||||
return clientHelper.createClient(firstName, lastName);
|
||||
}
|
||||
|
||||
protected Long createLoanProduct(PostLoanProductsRequest request) {
|
||||
return loanHelper.createLoanProduct(request);
|
||||
}
|
||||
|
||||
protected Long applyForLoan(PostLoansRequest request) {
|
||||
return loanHelper.applyForLoan(request);
|
||||
}
|
||||
|
||||
protected Long approveLoan(Long loanId, PostLoansLoanIdRequest request) {
|
||||
return loanHelper.approveLoan(loanId, request);
|
||||
}
|
||||
|
||||
protected Long disburseLoan(Long loanId, PostLoansLoanIdRequest request) {
|
||||
return loanHelper.disburseLoan(loanId, request);
|
||||
}
|
||||
|
||||
protected GetLoansLoanIdResponse getLoanDetails(Long loanId) {
|
||||
return loanHelper.getLoanDetails(loanId);
|
||||
}
|
||||
|
||||
protected void undoApproval(Long loanId) {
|
||||
loanHelper.undoApproval(loanId);
|
||||
}
|
||||
|
||||
protected void undoDisbursement(Long loanId) {
|
||||
loanHelper.undoDisbursement(loanId);
|
||||
}
|
||||
|
||||
protected Long addRepayment(Long loanId, PostLoansLoanIdTransactionsRequest request) {
|
||||
return transactionHelper.addRepayment(loanId, request);
|
||||
}
|
||||
|
||||
protected Long addInterestWaiver(Long loanId, PostLoansLoanIdTransactionsRequest request) {
|
||||
return transactionHelper.addInterestWaiver(loanId, request);
|
||||
}
|
||||
|
||||
protected Long chargeOff(Long loanId, PostLoansLoanIdTransactionsRequest request) {
|
||||
return transactionHelper.chargeOff(loanId, request);
|
||||
}
|
||||
|
||||
protected Long addChargeback(Long loanId, Long transactionId, PostLoansLoanIdTransactionsRequest request) {
|
||||
return transactionHelper.addChargeback(loanId, transactionId, request);
|
||||
}
|
||||
|
||||
protected void undoRepayment(Long loanId, Long transactionId, String transactionDate) {
|
||||
transactionHelper.undoRepayment(loanId, transactionId, transactionDate);
|
||||
}
|
||||
|
||||
protected void verifyJournalEntries(Long loanId, LoanTestData.Journal... expectedEntries) {
|
||||
journalHelper.verifyJournalEntries(loanId, expectedEntries);
|
||||
}
|
||||
|
||||
protected void verifyJournalEntriesSequentially(Long loanId, LoanTestData.Journal... expectedEntries) {
|
||||
journalHelper.verifyJournalEntriesSequentially(loanId, expectedEntries);
|
||||
}
|
||||
|
||||
protected void runAt(String date, Runnable action) {
|
||||
businessDateHelper.runAt(date, action);
|
||||
}
|
||||
|
||||
protected void updateBusinessDate(String type, String date) {
|
||||
businessDateHelper.updateBusinessDate(type, date);
|
||||
}
|
||||
|
||||
protected void validateRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, LocalDate dueDate, double principalDue,
|
||||
double principalPaid, double principalOutstanding) {
|
||||
LoanTestValidators.validateRepaymentPeriod(loanDetails, index, dueDate, principalDue, principalPaid, principalOutstanding, 0.0,
|
||||
0.0);
|
||||
}
|
||||
|
||||
protected void validateRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, LocalDate dueDate, double principalDue,
|
||||
double principalPaid, double principalOutstanding, double paidInAdvance, double paidLate) {
|
||||
LoanTestValidators.validateRepaymentPeriod(loanDetails, index, dueDate, principalDue, principalPaid, principalOutstanding,
|
||||
paidInAdvance, paidLate);
|
||||
}
|
||||
|
||||
protected void verifyLoanStatus(GetLoansLoanIdResponse loanDetails, Function<GetLoansLoanIdStatus, Boolean> extractor) {
|
||||
LoanTestValidators.verifyLoanStatus(loanDetails, extractor);
|
||||
}
|
||||
|
||||
protected Long createApproveAndDisburseLoan(Long clientId, Long productId, String date, Double principal, Integer numberOfRepayments) {
|
||||
PostLoansRequest applyRequest = LoanRequestBuilders.applyLoan(clientId, productId, date, principal, numberOfRepayments);
|
||||
Long loanId = applyForLoan(applyRequest);
|
||||
|
||||
PostLoansLoanIdRequest approveRequest = LoanRequestBuilders.approveLoan(principal, date);
|
||||
approveLoan(loanId, approveRequest);
|
||||
|
||||
PostLoansLoanIdRequest disburseRequest = LoanRequestBuilders.disburseLoan(principal, date);
|
||||
disburseLoan(loanId, disburseRequest);
|
||||
|
||||
return loanId;
|
||||
}
|
||||
|
||||
protected Long createApprovedLoan(Long clientId, Long productId, String date, Double principal, Integer numberOfRepayments) {
|
||||
PostLoansRequest applyRequest = LoanRequestBuilders.applyLoan(clientId, productId, date, principal, numberOfRepayments);
|
||||
Long loanId = applyForLoan(applyRequest);
|
||||
|
||||
PostLoansLoanIdRequest approveRequest = LoanRequestBuilders.approveLoan(principal, date);
|
||||
approveLoan(loanId, approveRequest);
|
||||
|
||||
return loanId;
|
||||
}
|
||||
|
||||
protected LoanTestData.Journal debit(Long glAccountId, double amount) {
|
||||
return LoanTestData.Journal.debit(glAccountId, amount);
|
||||
}
|
||||
|
||||
protected LoanTestData.Journal credit(Long glAccountId, double amount) {
|
||||
return LoanTestData.Journal.credit(glAccountId, amount);
|
||||
}
|
||||
|
||||
protected PostLoansLoanIdTransactionsRequest repayment(double amount, String date) {
|
||||
return LoanRequestBuilders.repayLoan(amount, date);
|
||||
}
|
||||
|
||||
protected PostLoansLoanIdTransactionsRequest waiveInterest(double amount, String date) {
|
||||
return LoanRequestBuilders.waiveInterest(amount, date);
|
||||
}
|
||||
|
||||
protected PostLoansLoanIdTransactionsRequest chargeOff(String date) {
|
||||
return LoanRequestBuilders.chargeOff(date);
|
||||
}
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.client.feign.helpers;
|
||||
|
||||
import static org.apache.fineract.client.feign.util.FeignCalls.ok;
|
||||
|
||||
import java.util.Collections;
|
||||
import org.apache.fineract.client.feign.FineractFeignClient;
|
||||
import org.apache.fineract.client.models.GetGLAccountsResponse;
|
||||
import org.apache.fineract.client.models.PostGLAccountsRequest;
|
||||
import org.apache.fineract.client.models.PostGLAccountsResponse;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.apache.fineract.integrationtests.common.accounting.Account;
|
||||
|
||||
public class FeignAccountHelper {
|
||||
|
||||
private final FineractFeignClient fineractClient;
|
||||
|
||||
public FeignAccountHelper(FineractFeignClient fineractClient) {
|
||||
this.fineractClient = fineractClient;
|
||||
}
|
||||
|
||||
public Account createAssetAccount(String name) {
|
||||
return createAccount(name, "1", "ASSET");
|
||||
}
|
||||
|
||||
public Account createLiabilityAccount(String name) {
|
||||
return createAccount(name, "2", "LIABILITY");
|
||||
}
|
||||
|
||||
public Account createIncomeAccount(String name) {
|
||||
return createAccount(name, "4", "INCOME");
|
||||
}
|
||||
|
||||
public Account createExpenseAccount(String name) {
|
||||
return createAccount(name, "5", "EXPENSE");
|
||||
}
|
||||
|
||||
private Account createAccount(String name, String glCode, String type) {
|
||||
String uniqueName = Utils.uniqueRandomStringGenerator(name + "_", 4);
|
||||
String accountCode = Utils.uniqueRandomStringGenerator("GL_" + glCode, 6);
|
||||
|
||||
PostGLAccountsRequest request = new PostGLAccountsRequest()//
|
||||
.name(uniqueName)//
|
||||
.glCode(accountCode)//
|
||||
.manualEntriesAllowed(true)//
|
||||
.type(getAccountTypeId(type))//
|
||||
.usage(1);
|
||||
|
||||
PostGLAccountsResponse response = ok(() -> fineractClient.generalLedgerAccount().createGLAccount1(request));
|
||||
|
||||
GetGLAccountsResponse account = ok(
|
||||
() -> fineractClient.generalLedgerAccount().retreiveAccount(response.getResourceId(), Collections.emptyMap()));
|
||||
|
||||
return new Account(account.getId().intValue(), getAccountType(type));
|
||||
}
|
||||
|
||||
private Integer getAccountTypeId(String type) {
|
||||
return switch (type) {
|
||||
case "ASSET" -> 1;
|
||||
case "LIABILITY" -> 2;
|
||||
case "EQUITY" -> 3;
|
||||
case "INCOME" -> 4;
|
||||
case "EXPENSE" -> 5;
|
||||
default -> throw new IllegalArgumentException("Unknown account type: " + type);
|
||||
};
|
||||
}
|
||||
|
||||
private Account.AccountType getAccountType(String type) {
|
||||
return switch (type) {
|
||||
case "ASSET" -> Account.AccountType.ASSET;
|
||||
case "LIABILITY" -> Account.AccountType.LIABILITY;
|
||||
case "EQUITY" -> Account.AccountType.EQUITY;
|
||||
case "INCOME" -> Account.AccountType.INCOME;
|
||||
case "EXPENSE" -> Account.AccountType.EXPENSE;
|
||||
default -> throw new IllegalArgumentException("Unknown account type: " + type);
|
||||
};
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.client.feign.helpers;
|
||||
|
||||
import static org.apache.fineract.client.feign.util.FeignCalls.ok;
|
||||
|
||||
import java.util.Collections;
|
||||
import org.apache.fineract.client.feign.FineractFeignClient;
|
||||
import org.apache.fineract.client.models.BusinessDateResponse;
|
||||
import org.apache.fineract.client.models.BusinessDateUpdateRequest;
|
||||
import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData;
|
||||
|
||||
public class FeignBusinessDateHelper {
|
||||
|
||||
private final FineractFeignClient fineractClient;
|
||||
|
||||
public FeignBusinessDateHelper(FineractFeignClient fineractClient) {
|
||||
this.fineractClient = fineractClient;
|
||||
}
|
||||
|
||||
public BusinessDateResponse getBusinessDate(String type) {
|
||||
return ok(() -> fineractClient.businessDateManagement().getBusinessDate(type));
|
||||
}
|
||||
|
||||
public void updateBusinessDate(String type, String date) {
|
||||
BusinessDateUpdateRequest request = new BusinessDateUpdateRequest()//
|
||||
.type(BusinessDateUpdateRequest.TypeEnum.fromValue(type))//
|
||||
.date(date)//
|
||||
.dateFormat("yyyy-MM-dd")//
|
||||
.locale(LoanTestData.LOCALE);
|
||||
|
||||
ok(() -> fineractClient.businessDateManagement().updateBusinessDate(request, Collections.emptyMap()));
|
||||
}
|
||||
|
||||
public void runAt(String date, Runnable action) {
|
||||
BusinessDateResponse originalDate = getBusinessDate("BUSINESS_DATE");
|
||||
try {
|
||||
updateBusinessDate("BUSINESS_DATE", date);
|
||||
action.run();
|
||||
} finally {
|
||||
if (originalDate != null && originalDate.getDate() != null) {
|
||||
updateBusinessDate("BUSINESS_DATE", originalDate.getDate().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.client.feign.helpers;
|
||||
|
||||
import static org.apache.fineract.client.feign.util.FeignCalls.ok;
|
||||
|
||||
import java.util.Collections;
|
||||
import org.apache.fineract.client.feign.FineractFeignClient;
|
||||
import org.apache.fineract.client.models.GetClientsClientIdResponse;
|
||||
import org.apache.fineract.client.models.PostClientsRequest;
|
||||
import org.apache.fineract.client.models.PostClientsResponse;
|
||||
import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
|
||||
public class FeignClientHelper {
|
||||
|
||||
private final FineractFeignClient fineractClient;
|
||||
|
||||
public FeignClientHelper(FineractFeignClient fineractClient) {
|
||||
this.fineractClient = fineractClient;
|
||||
}
|
||||
|
||||
public Long createClient(String firstName, String lastName) {
|
||||
String externalId = Utils.randomStringGenerator("EXT_", 7);
|
||||
String activationDate = Utils.dateFormatter.format(Utils.getLocalDateOfTenant());
|
||||
|
||||
PostClientsRequest request = new PostClientsRequest()//
|
||||
.officeId(1L)//
|
||||
.legalFormId(1L)//
|
||||
.firstname(firstName)//
|
||||
.lastname(lastName)//
|
||||
.externalId(externalId)//
|
||||
.active(true)//
|
||||
.activationDate(activationDate)//
|
||||
.dateFormat(LoanTestData.DATETIME_PATTERN)//
|
||||
.locale(LoanTestData.LOCALE);
|
||||
|
||||
return createClient(request);
|
||||
}
|
||||
|
||||
public Long createClient(PostClientsRequest request) {
|
||||
PostClientsResponse response = ok(() -> fineractClient.clients().create6(request));
|
||||
return response.getClientId();
|
||||
}
|
||||
|
||||
public GetClientsClientIdResponse getClient(Long clientId) {
|
||||
return ok(() -> fineractClient.clients().retrieveOne11(clientId, Collections.emptyMap()));
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.client.feign.helpers;
|
||||
|
||||
import static org.apache.fineract.client.feign.util.FeignCalls.ok;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.client.feign.FineractFeignClient;
|
||||
import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse;
|
||||
import org.apache.fineract.client.models.JournalEntryTransactionItem;
|
||||
import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData;
|
||||
|
||||
public class FeignJournalEntryHelper {
|
||||
|
||||
private final FineractFeignClient fineractClient;
|
||||
|
||||
public FeignJournalEntryHelper(FineractFeignClient fineractClient) {
|
||||
this.fineractClient = fineractClient;
|
||||
}
|
||||
|
||||
public GetJournalEntriesTransactionIdResponse getJournalEntriesForLoan(Long loanId) {
|
||||
return ok(() -> fineractClient.journalEntries().retrieveAll1(Map.of("loanId", loanId)));
|
||||
}
|
||||
|
||||
public void verifyJournalEntries(Long loanId, LoanTestData.Journal... expectedEntries) {
|
||||
GetJournalEntriesTransactionIdResponse journalEntries = getJournalEntriesForLoan(loanId);
|
||||
assertNotNull(journalEntries);
|
||||
assertNotNull(journalEntries.getPageItems());
|
||||
|
||||
List<JournalEntryTransactionItem> actualEntries = journalEntries.getPageItems();
|
||||
assertEquals(expectedEntries.length, actualEntries.size(),
|
||||
"Expected " + expectedEntries.length + " journal entries but found " + actualEntries.size());
|
||||
|
||||
for (int i = 0; i < expectedEntries.length; i++) {
|
||||
LoanTestData.Journal expected = expectedEntries[i];
|
||||
JournalEntryTransactionItem actual = actualEntries.get(i);
|
||||
|
||||
Double expectedAmount = expected.amount;
|
||||
Double actualAmount = actual.getAmount();
|
||||
assertEquals(0, Double.compare(expectedAmount, actualAmount),
|
||||
"Journal entry " + i + " amount mismatch: expected " + expectedAmount + " but got " + actualAmount);
|
||||
assertEquals(expected.account.getAccountID().longValue(), actual.getGlAccountId(), "Journal entry " + i + " account mismatch");
|
||||
assertEquals(expected.type, actual.getEntryType().getValue(), "Journal entry " + i + " type mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
public void verifyJournalEntriesSequentially(Long loanId, LoanTestData.Journal... expectedEntries) {
|
||||
verifyJournalEntries(loanId, expectedEntries);
|
||||
}
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.client.feign.helpers;
|
||||
|
||||
import static org.apache.fineract.client.feign.util.FeignCalls.ok;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.client.feign.FineractFeignClient;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.PostLoanProductsRequest;
|
||||
import org.apache.fineract.client.models.PostLoanProductsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdRequest;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.PostLoansRequest;
|
||||
import org.apache.fineract.client.models.PostLoansResponse;
|
||||
|
||||
public class FeignLoanHelper {
|
||||
|
||||
private final FineractFeignClient fineractClient;
|
||||
|
||||
public FeignLoanHelper(FineractFeignClient fineractClient) {
|
||||
this.fineractClient = fineractClient;
|
||||
}
|
||||
|
||||
public Long createLoanProduct(PostLoanProductsRequest request) {
|
||||
PostLoanProductsResponse response = ok(() -> fineractClient.loanProducts().createLoanProduct(request));
|
||||
return response.getResourceId();
|
||||
}
|
||||
|
||||
public Long applyForLoan(PostLoansRequest request) {
|
||||
PostLoansResponse response = ok(() -> fineractClient.loans().calculateLoanScheduleOrSubmitLoanApplication(request, null));
|
||||
return response.getLoanId();
|
||||
}
|
||||
|
||||
public Long approveLoan(Long loanId, PostLoansLoanIdRequest request) {
|
||||
PostLoansLoanIdResponse response = ok(() -> fineractClient.loans().stateTransitions(loanId, request, Map.of("command", "approve")));
|
||||
return response.getLoanId();
|
||||
}
|
||||
|
||||
public Long disburseLoan(Long loanId, PostLoansLoanIdRequest request) {
|
||||
PostLoansLoanIdResponse response = ok(
|
||||
() -> fineractClient.loans().stateTransitions(loanId, request, Map.of("command", "disburse")));
|
||||
return response.getLoanId();
|
||||
}
|
||||
|
||||
public GetLoansLoanIdResponse getLoanDetails(Long loanId) {
|
||||
return ok(() -> fineractClient.loans().retrieveLoan(loanId, Map.of("associations", "all", "exclude", "guarantors,futureSchedule")));
|
||||
}
|
||||
|
||||
public void undoApproval(Long loanId) {
|
||||
PostLoansLoanIdRequest request = new PostLoansLoanIdRequest();
|
||||
ok(() -> fineractClient.loans().stateTransitions(loanId, request, Map.of("command", "undoApproval")));
|
||||
}
|
||||
|
||||
public void undoDisbursement(Long loanId) {
|
||||
PostLoansLoanIdRequest request = new PostLoansLoanIdRequest();
|
||||
ok(() -> fineractClient.loans().stateTransitions(loanId, request, Map.of("command", "undoDisbursal")));
|
||||
}
|
||||
|
||||
public Long applyAndApproveLoan(Long clientId, Long productId, String submittedOnDate, Double principal, Integer numberOfRepayments) {
|
||||
PostLoansRequest applyRequest = new PostLoansRequest()//
|
||||
.clientId(clientId)//
|
||||
.productId(productId)//
|
||||
.loanType("individual")//
|
||||
.submittedOnDate(submittedOnDate)//
|
||||
.expectedDisbursementDate(submittedOnDate)//
|
||||
.principal(BigDecimal.valueOf(principal))//
|
||||
.loanTermFrequency(numberOfRepayments)//
|
||||
.loanTermFrequencyType(2)//
|
||||
.numberOfRepayments(numberOfRepayments)//
|
||||
.repaymentEvery(1)//
|
||||
.repaymentFrequencyType(2)//
|
||||
.interestRatePerPeriod(BigDecimal.ZERO)//
|
||||
.amortizationType(1)//
|
||||
.interestType(0)//
|
||||
.interestCalculationPeriodType(1)//
|
||||
.transactionProcessingStrategyCode("mifos-standard-strategy")//
|
||||
.locale("en")//
|
||||
.dateFormat("dd MMMM yyyy");
|
||||
|
||||
Long loanId = applyForLoan(applyRequest);
|
||||
|
||||
PostLoansLoanIdRequest approveRequest = new PostLoansLoanIdRequest()//
|
||||
.approvedLoanAmount(BigDecimal.valueOf(principal))//
|
||||
.approvedOnDate(submittedOnDate)//
|
||||
.locale("en")//
|
||||
.dateFormat("dd MMMM yyyy");
|
||||
|
||||
approveLoan(loanId, approveRequest);
|
||||
return loanId;
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.client.feign.helpers;
|
||||
|
||||
import static org.apache.fineract.client.feign.util.FeignCalls.ok;
|
||||
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.client.feign.FineractFeignClient;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest;
|
||||
|
||||
public class FeignTransactionHelper {
|
||||
|
||||
private final FineractFeignClient fineractClient;
|
||||
|
||||
public FeignTransactionHelper(FineractFeignClient fineractClient) {
|
||||
this.fineractClient = fineractClient;
|
||||
}
|
||||
|
||||
public Long addRepayment(Long loanId, PostLoansLoanIdTransactionsRequest request) {
|
||||
PostLoansLoanIdTransactionsResponse response = ok(
|
||||
() -> fineractClient.loanTransactions().executeLoanTransaction(loanId, request, Map.of("command", "repayment")));
|
||||
return response.getResourceId();
|
||||
}
|
||||
|
||||
public Long addInterestWaiver(Long loanId, PostLoansLoanIdTransactionsRequest request) {
|
||||
PostLoansLoanIdTransactionsResponse response = ok(
|
||||
() -> fineractClient.loanTransactions().executeLoanTransaction(loanId, request, Map.of("command", "waiveInterest")));
|
||||
return response.getResourceId();
|
||||
}
|
||||
|
||||
public Long chargeOff(Long loanId, PostLoansLoanIdTransactionsRequest request) {
|
||||
PostLoansLoanIdTransactionsResponse response = ok(
|
||||
() -> fineractClient.loanTransactions().executeLoanTransaction(loanId, request, Map.of("command", "chargeOff")));
|
||||
return response.getResourceId();
|
||||
}
|
||||
|
||||
public Long addChargeback(Long loanId, Long transactionId, PostLoansLoanIdTransactionsRequest request) {
|
||||
PostLoansLoanIdTransactionsTransactionIdRequest chargebackRequest = new PostLoansLoanIdTransactionsTransactionIdRequest()//
|
||||
.transactionDate(request.getTransactionDate())//
|
||||
.transactionAmount(request.getTransactionAmount())//
|
||||
.locale(request.getLocale())//
|
||||
.dateFormat(request.getDateFormat());
|
||||
|
||||
PostLoansLoanIdTransactionsResponse response = ok(() -> fineractClient.loanTransactions().adjustLoanTransaction(loanId,
|
||||
transactionId, chargebackRequest, Map.of("command", "chargeback")));
|
||||
return response.getResourceId();
|
||||
}
|
||||
|
||||
public void undoRepayment(Long loanId, Long transactionId, String transactionDate) {
|
||||
PostLoansLoanIdTransactionsTransactionIdRequest request = new PostLoansLoanIdTransactionsTransactionIdRequest();
|
||||
request.setTransactionDate(transactionDate);
|
||||
request.setTransactionAmount(0.0);
|
||||
request.setDateFormat("dd MMMM yyyy");
|
||||
request.setLocale("en");
|
||||
ok(() -> fineractClient.loanTransactions().adjustLoanTransaction(loanId, transactionId, request, Map.of("command", "undo")));
|
||||
}
|
||||
}
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.client.feign.modules;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import org.apache.fineract.client.models.AllowAttributeOverrides;
|
||||
import org.apache.fineract.client.models.PostLoanProductsRequest;
|
||||
import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData.AmortizationType;
|
||||
import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData.DaysInMonthType;
|
||||
import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData.DaysInYearType;
|
||||
import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData.InterestCalculationPeriodType;
|
||||
import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData.InterestRateFrequencyType;
|
||||
import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData.InterestType;
|
||||
import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData.RepaymentFrequencyType;
|
||||
import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData.RescheduleStrategyMethod;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
||||
|
||||
public interface LoanProductTemplates {
|
||||
|
||||
Long getAssetAccountId(String accountName);
|
||||
|
||||
Long getLiabilityAccountId(String accountName);
|
||||
|
||||
Long getIncomeAccountId(String accountName);
|
||||
|
||||
Long getExpenseAccountId(String accountName);
|
||||
|
||||
default PostLoanProductsRequest onePeriod30DaysNoInterest() {
|
||||
return new PostLoanProductsRequest().name(Utils.uniqueRandomStringGenerator("LOAN_PRODUCT_", 6))//
|
||||
.shortName(Utils.uniqueRandomStringGenerator("", 4))//
|
||||
.description("Loan Product Description")//
|
||||
.includeInBorrowerCycle(false)//
|
||||
.currencyCode("USD")//
|
||||
.digitsAfterDecimal(2)//
|
||||
.inMultiplesOf(0)//
|
||||
.installmentAmountInMultiplesOf(1)//
|
||||
.useBorrowerCycle(false)//
|
||||
.minPrincipal(100.0)//
|
||||
.principal(1000.0)//
|
||||
.maxPrincipal(100000.0)//
|
||||
.minNumberOfRepayments(1)//
|
||||
.numberOfRepayments(1)//
|
||||
.maxNumberOfRepayments(30)//
|
||||
.isLinkedToFloatingInterestRates(false)//
|
||||
.minInterestRatePerPeriod(0.0)//
|
||||
.interestRatePerPeriod(0.0)//
|
||||
.maxInterestRatePerPeriod(100.0)//
|
||||
.interestRateFrequencyType(InterestRateFrequencyType.MONTHS)//
|
||||
.repaymentEvery(30)//
|
||||
.repaymentFrequencyType(RepaymentFrequencyType.DAYS_L)//
|
||||
.amortizationType(AmortizationType.EQUAL_INSTALLMENTS)//
|
||||
.interestType(InterestType.DECLINING_BALANCE)//
|
||||
.isEqualAmortization(false)//
|
||||
.interestCalculationPeriodType(InterestCalculationPeriodType.SAME_AS_REPAYMENT_PERIOD)//
|
||||
.transactionProcessingStrategyCode(
|
||||
LoanProductTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY)//
|
||||
.loanScheduleType(LoanScheduleType.CUMULATIVE.toString())//
|
||||
.daysInYearType(DaysInYearType.ACTUAL)//
|
||||
.daysInMonthType(DaysInMonthType.ACTUAL)//
|
||||
.canDefineInstallmentAmount(true)//
|
||||
.graceOnArrearsAgeing(3)//
|
||||
.overdueDaysForNPA(179)//
|
||||
.accountMovesOutOfNPAOnlyOnArrearsCompletion(false)//
|
||||
.principalThresholdForLastInstallment(50)//
|
||||
.allowVariableInstallments(false)//
|
||||
.canUseForTopup(false)//
|
||||
.isInterestRecalculationEnabled(false)//
|
||||
.holdGuaranteeFunds(false)//
|
||||
.multiDisburseLoan(true)//
|
||||
.allowAttributeOverrides(new AllowAttributeOverrides()//
|
||||
.amortizationType(true)//
|
||||
.interestType(true)//
|
||||
.transactionProcessingStrategyCode(true)//
|
||||
.interestCalculationPeriodType(true)//
|
||||
.inArrearsTolerance(true)//
|
||||
.repaymentEvery(true)//
|
||||
.graceOnPrincipalAndInterestPayment(true)//
|
||||
.graceOnArrearsAgeing(true))//
|
||||
.allowPartialPeriodInterestCalcualtion(true)//
|
||||
.maxTrancheCount(10)//
|
||||
.outstandingLoanBalance(10000.0)//
|
||||
.charges(Collections.emptyList())//
|
||||
.accountingRule(3)//
|
||||
.fundSourceAccountId(getLiabilityAccountId("fundSource"))//
|
||||
.loanPortfolioAccountId(getAssetAccountId("loansReceivable"))//
|
||||
.transfersInSuspenseAccountId(getAssetAccountId("suspense"))//
|
||||
.interestOnLoanAccountId(getIncomeAccountId("interestIncome"))//
|
||||
.incomeFromFeeAccountId(getIncomeAccountId("feeIncome"))//
|
||||
.incomeFromPenaltyAccountId(getIncomeAccountId("penaltyIncome"))//
|
||||
.incomeFromRecoveryAccountId(getIncomeAccountId("recoveries"))//
|
||||
.writeOffAccountId(getExpenseAccountId("writtenOff"))//
|
||||
.overpaymentLiabilityAccountId(getLiabilityAccountId("overpayment"))//
|
||||
.receivableInterestAccountId(getAssetAccountId("interestReceivable"))//
|
||||
.receivableFeeAccountId(getAssetAccountId("feeReceivable"))//
|
||||
.receivablePenaltyAccountId(getAssetAccountId("penaltyReceivable"))//
|
||||
.goodwillCreditAccountId(getExpenseAccountId("goodwillExpense"))//
|
||||
.incomeFromGoodwillCreditInterestAccountId(getIncomeAccountId("interestIncomeChargeOff"))//
|
||||
.incomeFromGoodwillCreditFeesAccountId(getIncomeAccountId("feeChargeOff"))//
|
||||
.incomeFromGoodwillCreditPenaltyAccountId(getIncomeAccountId("feeChargeOff"))//
|
||||
.incomeFromChargeOffInterestAccountId(getIncomeAccountId("interestIncomeChargeOff"))//
|
||||
.incomeFromChargeOffFeesAccountId(getIncomeAccountId("feeChargeOff"))//
|
||||
.incomeFromChargeOffPenaltyAccountId(getIncomeAccountId("penaltyChargeOff"))//
|
||||
.chargeOffExpenseAccountId(getExpenseAccountId("chargeOff"))//
|
||||
.chargeOffFraudExpenseAccountId(getExpenseAccountId("chargeOffFraud"))//
|
||||
.dateFormat(LoanTestData.DATETIME_PATTERN)//
|
||||
.locale("en_GB")//
|
||||
.disallowExpectedDisbursements(true)//
|
||||
.allowApprovedDisbursedAmountsOverApplied(true)//
|
||||
.overAppliedCalculationType("percentage")//
|
||||
.overAppliedNumber(50);
|
||||
}
|
||||
|
||||
default PostLoanProductsRequest fourInstallmentsCumulative() {
|
||||
return fourInstallmentsCumulativeTemplate().loanScheduleType(LoanScheduleType.CUMULATIVE.toString());
|
||||
}
|
||||
|
||||
default PostLoanProductsRequest fourInstallmentsProgressive() {
|
||||
return fourInstallmentsCumulativeTemplate().loanScheduleType("PROGRESSIVE").loanScheduleProcessingType("HORIZONTAL")
|
||||
.rescheduleStrategyMethod(RescheduleStrategyMethod.ADJUST_LAST_UNPAID_PERIOD);
|
||||
}
|
||||
|
||||
default PostLoanProductsRequest fourInstallmentsProgressiveWithCapitalizedIncome() {
|
||||
return fourInstallmentsProgressive().enableIncomeCapitalization(true)//
|
||||
.capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT)//
|
||||
.capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION)//
|
||||
.deferredIncomeLiabilityAccountId(getLiabilityAccountId("deferredIncomeLiability"))//
|
||||
.incomeFromCapitalizationAccountId(getIncomeAccountId("feeIncome"))//
|
||||
.capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE);
|
||||
}
|
||||
|
||||
default PostLoanProductsRequest fourInstallmentsCumulativeTemplate() {
|
||||
return new PostLoanProductsRequest().name(Utils.uniqueRandomStringGenerator("4I_PRODUCT_", 6))//
|
||||
.shortName(Utils.uniqueRandomStringGenerator("", 4))//
|
||||
.description("4 installment product")//
|
||||
.includeInBorrowerCycle(false)//
|
||||
.useBorrowerCycle(false)//
|
||||
.currencyCode("EUR")//
|
||||
.digitsAfterDecimal(2)//
|
||||
.principal(1000.0)//
|
||||
.minPrincipal(100.0)//
|
||||
.maxPrincipal(10000.0)//
|
||||
.numberOfRepayments(4)//
|
||||
.repaymentEvery(1)//
|
||||
.repaymentFrequencyType(RepaymentFrequencyType.MONTHS_L)//
|
||||
.interestRatePerPeriod(10.0)//
|
||||
.minInterestRatePerPeriod(0.0)//
|
||||
.maxInterestRatePerPeriod(120.0)//
|
||||
.interestRateFrequencyType(InterestRateFrequencyType.YEARS)//
|
||||
.isLinkedToFloatingInterestRates(false)//
|
||||
.allowVariableInstallments(false)//
|
||||
.amortizationType(AmortizationType.EQUAL_INSTALLMENTS)//
|
||||
.interestType(InterestType.DECLINING_BALANCE)//
|
||||
.interestCalculationPeriodType(InterestCalculationPeriodType.SAME_AS_REPAYMENT_PERIOD)//
|
||||
.allowPartialPeriodInterestCalcualtion(false)//
|
||||
.creditAllocation(List.of())//
|
||||
.overdueDaysForNPA(179)//
|
||||
.daysInMonthType(DaysInMonthType.DAYS_30)//
|
||||
.daysInYearType(DaysInYearType.DAYS_360)//
|
||||
.isInterestRecalculationEnabled(false)//
|
||||
.canDefineInstallmentAmount(true)//
|
||||
.repaymentStartDateType(1)//
|
||||
.charges(List.of())//
|
||||
.principalVariationsForBorrowerCycle(List.of())//
|
||||
.interestRateVariationsForBorrowerCycle(List.of())//
|
||||
.numberOfRepaymentVariationsForBorrowerCycle(List.of())//
|
||||
.accountingRule(3)//
|
||||
.canUseForTopup(false)//
|
||||
.fundSourceAccountId(getLiabilityAccountId("fundSource"))//
|
||||
.loanPortfolioAccountId(getAssetAccountId("loansReceivable"))//
|
||||
.transfersInSuspenseAccountId(getAssetAccountId("suspense"))//
|
||||
.interestOnLoanAccountId(getIncomeAccountId("interestIncome"))//
|
||||
.incomeFromFeeAccountId(getIncomeAccountId("feeIncome"))//
|
||||
.incomeFromPenaltyAccountId(getIncomeAccountId("penaltyIncome"))//
|
||||
.incomeFromRecoveryAccountId(getIncomeAccountId("recoveries"))//
|
||||
.writeOffAccountId(getExpenseAccountId("writtenOff"))//
|
||||
.overpaymentLiabilityAccountId(getLiabilityAccountId("overpayment"))//
|
||||
.receivableInterestAccountId(getAssetAccountId("interestReceivable"))//
|
||||
.receivableFeeAccountId(getAssetAccountId("feeReceivable"))//
|
||||
.receivablePenaltyAccountId(getAssetAccountId("penaltyReceivable"))//
|
||||
.goodwillCreditAccountId(getExpenseAccountId("goodwillExpense"))//
|
||||
.incomeFromGoodwillCreditInterestAccountId(getIncomeAccountId("interestIncomeChargeOff"))//
|
||||
.incomeFromGoodwillCreditFeesAccountId(getIncomeAccountId("feeChargeOff"))//
|
||||
.incomeFromGoodwillCreditPenaltyAccountId(getIncomeAccountId("feeChargeOff"))//
|
||||
.incomeFromChargeOffInterestAccountId(getIncomeAccountId("interestIncomeChargeOff"))//
|
||||
.incomeFromChargeOffFeesAccountId(getIncomeAccountId("feeChargeOff"))//
|
||||
.incomeFromChargeOffPenaltyAccountId(getIncomeAccountId("penaltyChargeOff"))//
|
||||
.chargeOffExpenseAccountId(getExpenseAccountId("chargeOff"))//
|
||||
.chargeOffFraudExpenseAccountId(getExpenseAccountId("chargeOffFraud"))//
|
||||
.dateFormat(LoanTestData.DATETIME_PATTERN)//
|
||||
.locale("en")//
|
||||
.enableAccrualActivityPosting(false)//
|
||||
.multiDisburseLoan(false)//
|
||||
.disallowExpectedDisbursements(false)//
|
||||
.allowApprovedDisbursedAmountsOverApplied(true)//
|
||||
.overAppliedCalculationType("percentage")//
|
||||
.overAppliedNumber(50)//
|
||||
.principalThresholdForLastInstallment(50)//
|
||||
.holdGuaranteeFunds(false)//
|
||||
.accountMovesOutOfNPAOnlyOnArrearsCompletion(false)//
|
||||
.allowAttributeOverrides(new AllowAttributeOverrides()//
|
||||
.amortizationType(true)//
|
||||
.interestType(true)//
|
||||
.transactionProcessingStrategyCode(true)//
|
||||
.interestCalculationPeriodType(true)//
|
||||
.inArrearsTolerance(true)//
|
||||
.repaymentEvery(true)//
|
||||
.graceOnPrincipalAndInterestPayment(true)//
|
||||
.graceOnArrearsAgeing(true))//
|
||||
.isEqualAmortization(false)//
|
||||
.enableDownPayment(false)//
|
||||
.enableInstallmentLevelDelinquency(false)//
|
||||
.transactionProcessingStrategyCode(
|
||||
LoanProductTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY);
|
||||
}
|
||||
|
||||
default PostLoanProductsRequest customizeProduct(PostLoanProductsRequest template,
|
||||
Function<PostLoanProductsRequest, PostLoanProductsRequest> customizer) {
|
||||
return customizer.apply(template);
|
||||
}
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.client.feign.modules;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdRequest;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
|
||||
import org.apache.fineract.client.models.PostLoansRequest;
|
||||
|
||||
public final class LoanRequestBuilders {
|
||||
|
||||
private LoanRequestBuilders() {}
|
||||
|
||||
public static PostLoansRequest applyLoan(Long clientId, Long productId, String submittedOnDate, Double principal,
|
||||
Integer numberOfRepayments) {
|
||||
return new PostLoansRequest()//
|
||||
.clientId(clientId)//
|
||||
.productId(productId)//
|
||||
.loanType("individual")//
|
||||
.submittedOnDate(submittedOnDate)//
|
||||
.expectedDisbursementDate(submittedOnDate)//
|
||||
.principal(BigDecimal.valueOf(principal))//
|
||||
.loanTermFrequency(numberOfRepayments)//
|
||||
.loanTermFrequencyType(LoanTestData.RepaymentFrequencyType.MONTHS)//
|
||||
.numberOfRepayments(numberOfRepayments)//
|
||||
.repaymentEvery(1)//
|
||||
.repaymentFrequencyType(LoanTestData.RepaymentFrequencyType.MONTHS)//
|
||||
.interestRatePerPeriod(BigDecimal.ZERO)//
|
||||
.amortizationType(LoanTestData.AmortizationType.EQUAL_INSTALLMENTS)//
|
||||
.interestType(LoanTestData.InterestType.DECLINING_BALANCE)//
|
||||
.interestCalculationPeriodType(LoanTestData.InterestCalculationPeriodType.SAME_AS_REPAYMENT_PERIOD)//
|
||||
.transactionProcessingStrategyCode("mifos-standard-strategy")//
|
||||
.locale(LoanTestData.LOCALE)//
|
||||
.dateFormat(LoanTestData.DATETIME_PATTERN);
|
||||
}
|
||||
|
||||
public static PostLoansRequest applyCumulativeLoan(Long clientId, Long productId, String submittedOnDate, Double principal,
|
||||
Integer numberOfRepayments, Double interestRate) {
|
||||
return new PostLoansRequest()//
|
||||
.clientId(clientId)//
|
||||
.productId(productId)//
|
||||
.submittedOnDate(submittedOnDate)//
|
||||
.expectedDisbursementDate(submittedOnDate)//
|
||||
.principal(BigDecimal.valueOf(principal))//
|
||||
.loanTermFrequency(numberOfRepayments)//
|
||||
.loanTermFrequencyType(LoanTestData.RepaymentFrequencyType.MONTHS)//
|
||||
.numberOfRepayments(numberOfRepayments)//
|
||||
.repaymentEvery(1)//
|
||||
.repaymentFrequencyType(LoanTestData.RepaymentFrequencyType.MONTHS)//
|
||||
.interestRatePerPeriod(BigDecimal.valueOf(interestRate))//
|
||||
.amortizationType(LoanTestData.AmortizationType.EQUAL_INSTALLMENTS)//
|
||||
.interestType(LoanTestData.InterestType.DECLINING_BALANCE)//
|
||||
.interestCalculationPeriodType(LoanTestData.InterestCalculationPeriodType.DAILY)//
|
||||
.transactionProcessingStrategyCode("DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY")//
|
||||
.loanType("individual")//
|
||||
.locale(LoanTestData.LOCALE)//
|
||||
.dateFormat(LoanTestData.DATETIME_PATTERN);
|
||||
}
|
||||
|
||||
public static PostLoansRequest applyProgressiveLoan(Long clientId, Long productId, String submittedOnDate, Double principal,
|
||||
Integer numberOfRepayments, Double interestRate) {
|
||||
return applyCumulativeLoan(clientId, productId, submittedOnDate, principal, numberOfRepayments, interestRate);
|
||||
}
|
||||
|
||||
public static PostLoansLoanIdRequest approveLoan(Double approvedAmount, String approvedOnDate) {
|
||||
return new PostLoansLoanIdRequest()//
|
||||
.approvedLoanAmount(BigDecimal.valueOf(approvedAmount))//
|
||||
.approvedOnDate(approvedOnDate)//
|
||||
.locale(LoanTestData.LOCALE)//
|
||||
.dateFormat(LoanTestData.DATETIME_PATTERN);
|
||||
}
|
||||
|
||||
public static PostLoansLoanIdRequest disburseLoan(Double disbursedAmount, String disbursedOnDate) {
|
||||
return new PostLoansLoanIdRequest()//
|
||||
.actualDisbursementDate(disbursedOnDate)//
|
||||
.transactionAmount(BigDecimal.valueOf(disbursedAmount))//
|
||||
.locale(LoanTestData.LOCALE)//
|
||||
.dateFormat(LoanTestData.DATETIME_PATTERN);
|
||||
}
|
||||
|
||||
public static PostLoansLoanIdTransactionsRequest repayLoan(Double amount, String transactionDate) {
|
||||
PostLoansLoanIdTransactionsRequest request = new PostLoansLoanIdTransactionsRequest();
|
||||
request.setTransactionDate(transactionDate);
|
||||
request.setTransactionAmount(amount);
|
||||
request.setLocale(LoanTestData.LOCALE);
|
||||
request.setDateFormat(LoanTestData.DATETIME_PATTERN);
|
||||
return request;
|
||||
}
|
||||
|
||||
public static PostLoansLoanIdTransactionsRequest makeWaiver(Double amount, String transactionDate) {
|
||||
PostLoansLoanIdTransactionsRequest request = new PostLoansLoanIdTransactionsRequest();
|
||||
request.setTransactionDate(transactionDate);
|
||||
request.setTransactionAmount(amount);
|
||||
request.setLocale(LoanTestData.LOCALE);
|
||||
request.setDateFormat(LoanTestData.DATETIME_PATTERN);
|
||||
return request;
|
||||
}
|
||||
|
||||
public static PostLoansLoanIdTransactionsRequest chargeOff(String transactionDate) {
|
||||
PostLoansLoanIdTransactionsRequest request = new PostLoansLoanIdTransactionsRequest();
|
||||
request.setTransactionDate(transactionDate);
|
||||
request.setLocale(LoanTestData.LOCALE);
|
||||
request.setDateFormat(LoanTestData.DATETIME_PATTERN);
|
||||
return request;
|
||||
}
|
||||
|
||||
public static PostLoansLoanIdTransactionsRequest addChargeback(Long transactionId, Double amount, String transactionDate) {
|
||||
PostLoansLoanIdTransactionsRequest request = new PostLoansLoanIdTransactionsRequest();
|
||||
request.setTransactionDate(transactionDate);
|
||||
request.setTransactionAmount(amount);
|
||||
request.setLocale(LoanTestData.LOCALE);
|
||||
request.setDateFormat(LoanTestData.DATETIME_PATTERN);
|
||||
return request;
|
||||
}
|
||||
|
||||
public static PostLoansLoanIdTransactionsRequest waiveInterest(Double amount, String transactionDate) {
|
||||
return makeWaiver(amount, transactionDate);
|
||||
}
|
||||
}
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.client.feign.modules;
|
||||
|
||||
import org.apache.fineract.integrationtests.client.feign.helpers.FeignAccountHelper;
|
||||
import org.apache.fineract.integrationtests.common.accounting.Account;
|
||||
|
||||
public class LoanTestAccounts implements LoanProductTemplates {
|
||||
|
||||
private final Account loansReceivableAccount;
|
||||
private final Account interestReceivableAccount;
|
||||
private final Account feeReceivableAccount;
|
||||
private final Account penaltyReceivableAccount;
|
||||
private final Account suspenseAccount;
|
||||
private final Account fundSource;
|
||||
private final Account overpaymentAccount;
|
||||
private final Account interestIncomeAccount;
|
||||
private final Account feeIncomeAccount;
|
||||
private final Account penaltyIncomeAccount;
|
||||
private final Account feeChargeOffAccount;
|
||||
private final Account penaltyChargeOffAccount;
|
||||
private final Account recoveriesAccount;
|
||||
private final Account interestIncomeChargeOffAccount;
|
||||
private final Account chargeOffExpenseAccount;
|
||||
private final Account chargeOffFraudExpenseAccount;
|
||||
private final Account writtenOffAccount;
|
||||
private final Account goodwillExpenseAccount;
|
||||
private final Account goodwillIncomeAccount;
|
||||
private final Account deferredIncomeLiabilityAccount;
|
||||
private final Account buyDownExpenseAccount;
|
||||
|
||||
public LoanTestAccounts(FeignAccountHelper accountHelper) {
|
||||
this.loansReceivableAccount = accountHelper.createAssetAccount("loanPortfolio");
|
||||
this.interestReceivableAccount = accountHelper.createAssetAccount("interestReceivable");
|
||||
this.feeReceivableAccount = accountHelper.createAssetAccount("feeReceivable");
|
||||
this.penaltyReceivableAccount = accountHelper.createAssetAccount("penaltyReceivable");
|
||||
this.suspenseAccount = accountHelper.createAssetAccount("suspense");
|
||||
this.fundSource = accountHelper.createLiabilityAccount("fundSource");
|
||||
this.overpaymentAccount = accountHelper.createLiabilityAccount("overpayment");
|
||||
this.interestIncomeAccount = accountHelper.createIncomeAccount("interestIncome");
|
||||
this.feeIncomeAccount = accountHelper.createIncomeAccount("feeIncome");
|
||||
this.penaltyIncomeAccount = accountHelper.createIncomeAccount("penaltyIncome");
|
||||
this.feeChargeOffAccount = accountHelper.createIncomeAccount("feeChargeOff");
|
||||
this.penaltyChargeOffAccount = accountHelper.createIncomeAccount("penaltyChargeOff");
|
||||
this.recoveriesAccount = accountHelper.createIncomeAccount("recoveries");
|
||||
this.interestIncomeChargeOffAccount = accountHelper.createIncomeAccount("interestIncomeChargeOff");
|
||||
this.chargeOffExpenseAccount = accountHelper.createExpenseAccount("chargeOff");
|
||||
this.chargeOffFraudExpenseAccount = accountHelper.createExpenseAccount("chargeOffFraud");
|
||||
this.writtenOffAccount = accountHelper.createExpenseAccount("writtenOffAccount");
|
||||
this.goodwillExpenseAccount = accountHelper.createExpenseAccount("goodwillExpenseAccount");
|
||||
this.goodwillIncomeAccount = accountHelper.createIncomeAccount("goodwillIncomeAccount");
|
||||
this.deferredIncomeLiabilityAccount = accountHelper.createLiabilityAccount("deferredIncomeLiabilityAccount");
|
||||
this.buyDownExpenseAccount = accountHelper.createExpenseAccount("buyDownExpenseAccount");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getAssetAccountId(String accountName) {
|
||||
return switch (accountName) {
|
||||
case "loansReceivable" -> loansReceivableAccount.getAccountID().longValue();
|
||||
case "interestReceivable" -> interestReceivableAccount.getAccountID().longValue();
|
||||
case "feeReceivable" -> feeReceivableAccount.getAccountID().longValue();
|
||||
case "penaltyReceivable" -> penaltyReceivableAccount.getAccountID().longValue();
|
||||
case "suspense" -> suspenseAccount.getAccountID().longValue();
|
||||
default -> throw new IllegalArgumentException("Unknown asset account: " + accountName);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLiabilityAccountId(String accountName) {
|
||||
return switch (accountName) {
|
||||
case "fundSource" -> fundSource.getAccountID().longValue();
|
||||
case "overpayment" -> overpaymentAccount.getAccountID().longValue();
|
||||
case "deferredIncomeLiability" -> deferredIncomeLiabilityAccount.getAccountID().longValue();
|
||||
default -> throw new IllegalArgumentException("Unknown liability account: " + accountName);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getIncomeAccountId(String accountName) {
|
||||
return switch (accountName) {
|
||||
case "interestIncome" -> interestIncomeAccount.getAccountID().longValue();
|
||||
case "feeIncome" -> feeIncomeAccount.getAccountID().longValue();
|
||||
case "penaltyIncome" -> penaltyIncomeAccount.getAccountID().longValue();
|
||||
case "feeChargeOff" -> feeChargeOffAccount.getAccountID().longValue();
|
||||
case "penaltyChargeOff" -> penaltyChargeOffAccount.getAccountID().longValue();
|
||||
case "recoveries" -> recoveriesAccount.getAccountID().longValue();
|
||||
case "interestIncomeChargeOff" -> interestIncomeChargeOffAccount.getAccountID().longValue();
|
||||
case "goodwillIncome" -> goodwillIncomeAccount.getAccountID().longValue();
|
||||
default -> throw new IllegalArgumentException("Unknown income account: " + accountName);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getExpenseAccountId(String accountName) {
|
||||
return switch (accountName) {
|
||||
case "chargeOff" -> chargeOffExpenseAccount.getAccountID().longValue();
|
||||
case "chargeOffFraud" -> chargeOffFraudExpenseAccount.getAccountID().longValue();
|
||||
case "writtenOff" -> writtenOffAccount.getAccountID().longValue();
|
||||
case "goodwillExpense" -> goodwillExpenseAccount.getAccountID().longValue();
|
||||
case "buyDownExpense" -> buyDownExpenseAccount.getAccountID().longValue();
|
||||
default -> throw new IllegalArgumentException("Unknown expense account: " + accountName);
|
||||
};
|
||||
}
|
||||
|
||||
public Account getLoansReceivableAccount() {
|
||||
return loansReceivableAccount;
|
||||
}
|
||||
|
||||
public Account getInterestReceivableAccount() {
|
||||
return interestReceivableAccount;
|
||||
}
|
||||
|
||||
public Account getFeeReceivableAccount() {
|
||||
return feeReceivableAccount;
|
||||
}
|
||||
|
||||
public Account getPenaltyReceivableAccount() {
|
||||
return penaltyReceivableAccount;
|
||||
}
|
||||
|
||||
public Account getSuspenseAccount() {
|
||||
return suspenseAccount;
|
||||
}
|
||||
|
||||
public Account getFundSource() {
|
||||
return fundSource;
|
||||
}
|
||||
|
||||
public Account getOverpaymentAccount() {
|
||||
return overpaymentAccount;
|
||||
}
|
||||
|
||||
public Account getInterestIncomeAccount() {
|
||||
return interestIncomeAccount;
|
||||
}
|
||||
|
||||
public Account getFeeIncomeAccount() {
|
||||
return feeIncomeAccount;
|
||||
}
|
||||
|
||||
public Account getPenaltyIncomeAccount() {
|
||||
return penaltyIncomeAccount;
|
||||
}
|
||||
|
||||
public Account getFeeChargeOffAccount() {
|
||||
return feeChargeOffAccount;
|
||||
}
|
||||
|
||||
public Account getPenaltyChargeOffAccount() {
|
||||
return penaltyChargeOffAccount;
|
||||
}
|
||||
|
||||
public Account getRecoveriesAccount() {
|
||||
return recoveriesAccount;
|
||||
}
|
||||
|
||||
public Account getInterestIncomeChargeOffAccount() {
|
||||
return interestIncomeChargeOffAccount;
|
||||
}
|
||||
|
||||
public Account getChargeOffExpenseAccount() {
|
||||
return chargeOffExpenseAccount;
|
||||
}
|
||||
|
||||
public Account getChargeOffFraudExpenseAccount() {
|
||||
return chargeOffFraudExpenseAccount;
|
||||
}
|
||||
|
||||
public Account getWrittenOffAccount() {
|
||||
return writtenOffAccount;
|
||||
}
|
||||
|
||||
public Account getGoodwillExpenseAccount() {
|
||||
return goodwillExpenseAccount;
|
||||
}
|
||||
|
||||
public Account getGoodwillIncomeAccount() {
|
||||
return goodwillIncomeAccount;
|
||||
}
|
||||
|
||||
public Account getDeferredIncomeLiabilityAccount() {
|
||||
return deferredIncomeLiabilityAccount;
|
||||
}
|
||||
|
||||
public Account getBuyDownExpenseAccount() {
|
||||
return buyDownExpenseAccount;
|
||||
}
|
||||
}
|
||||
+231
@@ -0,0 +1,231 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.client.feign.modules;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import org.apache.fineract.integrationtests.common.accounting.Account;
|
||||
|
||||
public final class LoanTestData {
|
||||
|
||||
public static final String DATETIME_PATTERN = "dd MMMM yyyy";
|
||||
public static final String LOCALE = "en";
|
||||
|
||||
private LoanTestData() {}
|
||||
|
||||
@ToString
|
||||
@AllArgsConstructor
|
||||
public static class Transaction {
|
||||
|
||||
public Double amount;
|
||||
public String type;
|
||||
public String date;
|
||||
public Boolean reversed;
|
||||
}
|
||||
|
||||
@ToString
|
||||
@AllArgsConstructor
|
||||
public static class TransactionExt {
|
||||
|
||||
public Double amount;
|
||||
public String type;
|
||||
public String date;
|
||||
public Double outstandingPrincipal;
|
||||
public Double principalPortion;
|
||||
public Double interestPortion;
|
||||
public Double feePortion;
|
||||
public Double penaltyPortion;
|
||||
public Double unrecognizedPortion;
|
||||
public Double overpaymentPortion;
|
||||
public Boolean reversed;
|
||||
}
|
||||
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class Journal {
|
||||
|
||||
public Double amount;
|
||||
public Account account;
|
||||
public String type;
|
||||
|
||||
public static Journal debit(Long glAccountId, double amount) {
|
||||
Journal journal = new Journal();
|
||||
journal.amount = amount;
|
||||
journal.account = new Account(glAccountId.intValue(), null);
|
||||
journal.type = "DEBIT";
|
||||
return journal;
|
||||
}
|
||||
|
||||
public static Journal credit(Long glAccountId, double amount) {
|
||||
Journal journal = new Journal();
|
||||
journal.amount = amount;
|
||||
journal.account = new Account(glAccountId.intValue(), null);
|
||||
journal.type = "CREDIT";
|
||||
return journal;
|
||||
}
|
||||
}
|
||||
|
||||
@ToString
|
||||
@AllArgsConstructor
|
||||
public static class Installment {
|
||||
|
||||
public Double principalAmount;
|
||||
public Double interestAmount;
|
||||
public Double feeAmount;
|
||||
public Double penaltyAmount;
|
||||
public Double totalOutstandingAmount;
|
||||
public Boolean completed;
|
||||
public String dueDate;
|
||||
public OutstandingAmounts outstandingAmounts;
|
||||
public Double loanBalance;
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
public static class OutstandingAmounts {
|
||||
|
||||
public Double principalOutstanding;
|
||||
public Double interestOutstanding;
|
||||
public Double feeOutstanding;
|
||||
public Double penaltyOutstanding;
|
||||
public Double totalOutstanding;
|
||||
}
|
||||
|
||||
public static final class AmortizationType {
|
||||
|
||||
public static final Integer EQUAL_INSTALLMENTS = 1;
|
||||
|
||||
private AmortizationType() {}
|
||||
}
|
||||
|
||||
public static final class InterestType {
|
||||
|
||||
public static final Integer DECLINING_BALANCE = 0;
|
||||
public static final Integer FLAT = 1;
|
||||
|
||||
private InterestType() {}
|
||||
}
|
||||
|
||||
public static final class InterestRecalculationCompoundingMethod {
|
||||
|
||||
public static final Integer NONE = 0;
|
||||
|
||||
private InterestRecalculationCompoundingMethod() {}
|
||||
}
|
||||
|
||||
public static final class RepaymentFrequencyType {
|
||||
|
||||
public static final Integer MONTHS = 2;
|
||||
public static final Long MONTHS_L = 2L;
|
||||
public static final String MONTHS_STRING = "MONTHS";
|
||||
public static final Integer DAYS = 0;
|
||||
public static final Long DAYS_L = 0L;
|
||||
public static final String DAYS_STRING = "DAYS";
|
||||
|
||||
private RepaymentFrequencyType() {}
|
||||
}
|
||||
|
||||
public static final class RecalculationRestFrequencyType {
|
||||
|
||||
public static final Integer SAME_AS_REPAYMENT_PERIOD = 1;
|
||||
public static final Integer DAILY = 2;
|
||||
|
||||
private RecalculationRestFrequencyType() {}
|
||||
}
|
||||
|
||||
public static final class InterestCalculationPeriodType {
|
||||
|
||||
public static final Integer DAILY = 0;
|
||||
public static final Integer SAME_AS_REPAYMENT_PERIOD = 1;
|
||||
|
||||
private InterestCalculationPeriodType() {}
|
||||
}
|
||||
|
||||
public static final class InterestRateFrequencyType {
|
||||
|
||||
public static final Integer MONTHS = 2;
|
||||
public static final Integer YEARS = 3;
|
||||
public static final Integer WHOLE_TERM = 4;
|
||||
|
||||
private InterestRateFrequencyType() {}
|
||||
}
|
||||
|
||||
public static final class TransactionProcessingStrategyCode {
|
||||
|
||||
public static final String ADVANCED_PAYMENT_ALLOCATION_STRATEGY = "advanced-payment-allocation-strategy";
|
||||
|
||||
private TransactionProcessingStrategyCode() {}
|
||||
}
|
||||
|
||||
public static final class RescheduleStrategyMethod {
|
||||
|
||||
public static final Integer RESCHEDULE_NEXT_REPAYMENTS = 1;
|
||||
public static final Integer REDUCE_EMI_AMOUNT = 3;
|
||||
public static final Integer ADJUST_LAST_UNPAID_PERIOD = 4;
|
||||
|
||||
private RescheduleStrategyMethod() {}
|
||||
}
|
||||
|
||||
public static final class DaysInYearType {
|
||||
|
||||
public static final Integer INVALID = 0;
|
||||
public static final Integer ACTUAL = 1;
|
||||
public static final Integer DAYS_360 = 360;
|
||||
public static final Integer DAYS_364 = 364;
|
||||
public static final Integer DAYS_365 = 365;
|
||||
|
||||
private DaysInYearType() {}
|
||||
}
|
||||
|
||||
public static final class DaysInMonthType {
|
||||
|
||||
public static final Integer INVALID = 0;
|
||||
public static final Integer ACTUAL = 1;
|
||||
public static final Integer DAYS_30 = 30;
|
||||
|
||||
private DaysInMonthType() {}
|
||||
}
|
||||
|
||||
public static final class FuturePaymentAllocationRule {
|
||||
|
||||
public static final String LAST_INSTALLMENT = "LAST_INSTALLMENT";
|
||||
public static final String NEXT_INSTALLMENT = "NEXT_INSTALLMENT";
|
||||
public static final String NEXT_LAST_INSTALLMENT = "NEXT_LAST_INSTALLMENT";
|
||||
|
||||
private FuturePaymentAllocationRule() {}
|
||||
}
|
||||
|
||||
public static final class SupportedInterestRefundTypesItem {
|
||||
|
||||
public static final String MERCHANT_ISSUED_REFUND = "MERCHANT_ISSUED_REFUND";
|
||||
public static final String PAYOUT_REFUND = "PAYOUT_REFUND";
|
||||
|
||||
private SupportedInterestRefundTypesItem() {}
|
||||
}
|
||||
|
||||
public static final class DaysInYearCustomStrategy {
|
||||
|
||||
public static final String FEB_29_PERIOD_ONLY = "FEB_29_PERIOD_ONLY";
|
||||
public static final String FULL_LEAP_YEAR = "FULL_LEAP_YEAR";
|
||||
|
||||
private DaysInYearCustomStrategy() {}
|
||||
}
|
||||
}
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.client.feign.modules;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdStatus;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
|
||||
public final class LoanTestValidators {
|
||||
|
||||
private LoanTestValidators() {}
|
||||
|
||||
public 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, Utils.getDoubleValue(period.getPrincipalDue()));
|
||||
assertEquals(principalPaid, Utils.getDoubleValue(period.getPrincipalPaid()));
|
||||
assertEquals(principalOutstanding, Utils.getDoubleValue(period.getPrincipalOutstanding()));
|
||||
assertEquals(paidInAdvance, Utils.getDoubleValue(period.getTotalPaidInAdvanceForPeriod()));
|
||||
assertEquals(paidLate, Utils.getDoubleValue(period.getTotalPaidLateForPeriod()));
|
||||
}
|
||||
|
||||
public static void validateRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, 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(principalDue, Utils.getDoubleValue(period.getPrincipalDue()));
|
||||
assertEquals(principalPaid, Utils.getDoubleValue(period.getPrincipalPaid()));
|
||||
assertEquals(principalOutstanding, Utils.getDoubleValue(period.getPrincipalOutstanding()));
|
||||
assertEquals(paidInAdvance, Utils.getDoubleValue(period.getTotalPaidInAdvanceForPeriod()));
|
||||
assertEquals(paidLate, Utils.getDoubleValue(period.getTotalPaidLateForPeriod()));
|
||||
}
|
||||
|
||||
public static void validateFullyUnpaidRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, String dueDate,
|
||||
double principalDue, double feeDue, double penaltyDue, double interestDue) {
|
||||
validateRepaymentPeriod(loanDetails, index,
|
||||
LocalDate.parse(dueDate, DateTimeFormatter.ofPattern(LoanTestData.DATETIME_PATTERN, Locale.ENGLISH)), principalDue, 0,
|
||||
principalDue, feeDue, 0, feeDue, penaltyDue, 0, penaltyDue, interestDue, 0, interestDue, 0, 0);
|
||||
}
|
||||
|
||||
public static void validateFullyPaidRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, String dueDate,
|
||||
double principalDue, double feeDue, double penaltyDue, double interestDue) {
|
||||
validateRepaymentPeriod(loanDetails, index,
|
||||
LocalDate.parse(dueDate, DateTimeFormatter.ofPattern(LoanTestData.DATETIME_PATTERN, Locale.ENGLISH)), principalDue,
|
||||
principalDue, 0, feeDue, feeDue, 0, penaltyDue, penaltyDue, 0, interestDue, interestDue, 0, 0, 0);
|
||||
}
|
||||
|
||||
public static void validateFullyPaidRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, String dueDate,
|
||||
double principalDue, double feeDue, double penaltyDue, double interestDue, double paidLate) {
|
||||
validateRepaymentPeriod(loanDetails, index,
|
||||
LocalDate.parse(dueDate, DateTimeFormatter.ofPattern(LoanTestData.DATETIME_PATTERN, Locale.ENGLISH)), principalDue,
|
||||
principalDue, 0, feeDue, feeDue, 0, penaltyDue, penaltyDue, 0, interestDue, interestDue, 0, 0, paidLate);
|
||||
}
|
||||
|
||||
public static void validateFullyPaidRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, String dueDate,
|
||||
double principalDue, double feeDue, double penaltyDue, double interestDue, double paidLate, double paidInAdvance) {
|
||||
validateRepaymentPeriod(loanDetails, index,
|
||||
LocalDate.parse(dueDate, DateTimeFormatter.ofPattern(LoanTestData.DATETIME_PATTERN, Locale.ENGLISH)), principalDue,
|
||||
principalDue, 0, feeDue, feeDue, 0, penaltyDue, penaltyDue, 0, interestDue, interestDue, 0, paidInAdvance, paidLate);
|
||||
}
|
||||
|
||||
public static void validateRepaymentPeriod(GetLoansLoanIdResponse loanDetails, Integer index, LocalDate dueDate, double principalDue,
|
||||
double feeDue, double penaltyDue, double interestDue) {
|
||||
validateRepaymentPeriod(loanDetails, index, dueDate, principalDue, 0, principalDue, feeDue, 0, feeDue, penaltyDue, 0, penaltyDue,
|
||||
interestDue, 0, interestDue, 0, 0);
|
||||
}
|
||||
|
||||
public 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, Utils.getDoubleValue(period.getPrincipalDue()));
|
||||
assertEquals(principalPaid, Utils.getDoubleValue(period.getPrincipalPaid()));
|
||||
assertEquals(principalOutstanding, Utils.getDoubleValue(period.getPrincipalOutstanding()));
|
||||
assertEquals(feeDue, Utils.getDoubleValue(period.getFeeChargesDue()));
|
||||
assertEquals(feePaid, Utils.getDoubleValue(period.getFeeChargesPaid()));
|
||||
assertEquals(feeOutstanding, Utils.getDoubleValue(period.getFeeChargesOutstanding()));
|
||||
assertEquals(penaltyDue, Utils.getDoubleValue(period.getPenaltyChargesDue()));
|
||||
assertEquals(penaltyPaid, Utils.getDoubleValue(period.getPenaltyChargesPaid()));
|
||||
assertEquals(penaltyOutstanding, Utils.getDoubleValue(period.getPenaltyChargesOutstanding()));
|
||||
assertEquals(interestDue, Utils.getDoubleValue(period.getInterestDue()));
|
||||
assertEquals(interestPaid, Utils.getDoubleValue(period.getInterestPaid()));
|
||||
assertEquals(interestOutstanding, Utils.getDoubleValue(period.getInterestOutstanding()));
|
||||
assertEquals(paidInAdvance, Utils.getDoubleValue(period.getTotalPaidInAdvanceForPeriod()));
|
||||
assertEquals(paidLate, Utils.getDoubleValue(period.getTotalPaidLateForPeriod()));
|
||||
}
|
||||
|
||||
public static void verifyLoanStatus(GetLoansLoanIdResponse loanDetails, Function<GetLoansLoanIdStatus, Boolean> extractor) {
|
||||
assertNotNull(loanDetails);
|
||||
assertNotNull(loanDetails.getStatus());
|
||||
Boolean actualValue = extractor.apply(loanDetails.getStatus());
|
||||
assertNotNull(actualValue);
|
||||
assertTrue(actualValue);
|
||||
}
|
||||
}
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.client.feign.tests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.PostLoanProductsRequest;
|
||||
import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class FeignLoanCreationTest extends FeignLoanTestBase {
|
||||
|
||||
@Test
|
||||
void testCreateAndDisburseLoan_OnePeriodNoInterest() {
|
||||
Long clientId = createClient("John", "Doe");
|
||||
assertNotNull(clientId);
|
||||
|
||||
PostLoanProductsRequest productRequest = onePeriod30DaysNoInterest();
|
||||
Long productId = createLoanProduct(productRequest);
|
||||
assertNotNull(productId);
|
||||
|
||||
String todayDate = Utils.dateFormatter.format(Utils.getLocalDateOfTenant());
|
||||
Long loanId = createApproveAndDisburseLoan(clientId, productId, todayDate, 1000.0, 1);
|
||||
assertNotNull(loanId);
|
||||
|
||||
GetLoansLoanIdResponse loan = getLoanDetails(loanId);
|
||||
assertNotNull(loan);
|
||||
verifyLoanStatus(loan, status -> status.getActive());
|
||||
|
||||
LocalDate expectedRepaymentDate = Utils.getLocalDateOfTenant().plusMonths(1);
|
||||
validateRepaymentPeriod(loan, 1, expectedRepaymentDate, 1000.0, 0.0, 1000.0);
|
||||
|
||||
verifyJournalEntries(loanId, debit(getAccounts().getLoansReceivableAccount().getAccountID().longValue(), 1000.0),
|
||||
credit(getAccounts().getFundSource().getAccountID().longValue(), 1000.0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoanRepayment_FullRepayment() {
|
||||
Long clientId = createClient("Jane", "Smith");
|
||||
Long productId = createLoanProduct(onePeriod30DaysNoInterest());
|
||||
String todayDate = Utils.dateFormatter.format(Utils.getLocalDateOfTenant());
|
||||
Long loanId = createApproveAndDisburseLoan(clientId, productId, todayDate, 1000.0, 1);
|
||||
|
||||
Long repaymentId = addRepayment(loanId, repayment(1000.0, todayDate));
|
||||
assertNotNull(repaymentId);
|
||||
|
||||
GetLoansLoanIdResponse loan = getLoanDetails(loanId);
|
||||
verifyLoanStatus(loan, status -> status.getClosedObligationsMet());
|
||||
|
||||
assertEquals(0.0, Utils.getDoubleValue(loan.getSummary().getTotalOutstanding()));
|
||||
assertEquals(1000.0, Utils.getDoubleValue(loan.getSummary().getTotalRepayment()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoanUndoApproval() {
|
||||
Long clientId = createClient("Bob", "Johnson");
|
||||
Long productId = createLoanProduct(onePeriod30DaysNoInterest());
|
||||
String todayDate = Utils.dateFormatter.format(Utils.getLocalDateOfTenant());
|
||||
Long loanId = createApprovedLoan(clientId, productId, todayDate, 1000.0, 1);
|
||||
|
||||
GetLoansLoanIdResponse loanBeforeUndo = getLoanDetails(loanId);
|
||||
verifyLoanStatus(loanBeforeUndo, status -> status.getWaitingForDisbursal());
|
||||
|
||||
undoApproval(loanId);
|
||||
|
||||
GetLoansLoanIdResponse loanAfterUndo = getLoanDetails(loanId);
|
||||
verifyLoanStatus(loanAfterUndo, status -> status.getPendingApproval());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoanUndoDisbursement() {
|
||||
Long clientId = createClient("Alice", "Williams");
|
||||
Long productId = createLoanProduct(onePeriod30DaysNoInterest());
|
||||
String todayDate = Utils.dateFormatter.format(Utils.getLocalDateOfTenant());
|
||||
Long loanId = createApproveAndDisburseLoan(clientId, productId, todayDate, 1000.0, 1);
|
||||
|
||||
GetLoansLoanIdResponse loanBeforeUndo = getLoanDetails(loanId);
|
||||
verifyLoanStatus(loanBeforeUndo, status -> status.getActive());
|
||||
|
||||
undoDisbursement(loanId);
|
||||
|
||||
GetLoansLoanIdResponse loanAfterUndo = getLoanDetails(loanId);
|
||||
verifyLoanStatus(loanAfterUndo, status -> status.getWaitingForDisbursal());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFourInstallmentLoan_CumulativeInterest() {
|
||||
Long clientId = createClient("Charlie", "Brown");
|
||||
Long productId = createLoanProduct(fourInstallmentsCumulative());
|
||||
String todayDate = Utils.dateFormatter.format(Utils.getLocalDateOfTenant());
|
||||
Long loanId = createApproveAndDisburseLoan(clientId, productId, todayDate, 1000.0, 4);
|
||||
|
||||
GetLoansLoanIdResponse loan = getLoanDetails(loanId);
|
||||
verifyLoanStatus(loan, status -> status.getActive());
|
||||
|
||||
assertNotNull(loan.getRepaymentSchedule());
|
||||
assertNotNull(loan.getRepaymentSchedule().getPeriods());
|
||||
assertEquals(5, loan.getRepaymentSchedule().getPeriods().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPartialRepayment() {
|
||||
Long clientId = createClient("David", "Miller");
|
||||
Long productId = createLoanProduct(onePeriod30DaysNoInterest());
|
||||
String todayDate = Utils.dateFormatter.format(Utils.getLocalDateOfTenant());
|
||||
Long loanId = createApproveAndDisburseLoan(clientId, productId, todayDate, 1000.0, 1);
|
||||
|
||||
Long repaymentId = addRepayment(loanId, repayment(500.0, todayDate));
|
||||
assertNotNull(repaymentId);
|
||||
|
||||
GetLoansLoanIdResponse loan = getLoanDetails(loanId);
|
||||
verifyLoanStatus(loan, status -> status.getActive());
|
||||
|
||||
assertEquals(500.0, Utils.getDoubleValue(loan.getSummary().getTotalOutstanding()));
|
||||
assertEquals(500.0, Utils.getDoubleValue(loan.getSummary().getTotalRepayment()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUndoRepayment() {
|
||||
Long clientId = createClient("Eva", "Davis");
|
||||
Long productId = createLoanProduct(onePeriod30DaysNoInterest());
|
||||
String todayDate = Utils.dateFormatter.format(Utils.getLocalDateOfTenant());
|
||||
Long loanId = createApproveAndDisburseLoan(clientId, productId, todayDate, 1000.0, 1);
|
||||
|
||||
Long repaymentId = addRepayment(loanId, repayment(1000.0, todayDate));
|
||||
assertNotNull(repaymentId);
|
||||
|
||||
GetLoansLoanIdResponse loanAfterRepayment = getLoanDetails(loanId);
|
||||
verifyLoanStatus(loanAfterRepayment, status -> status.getClosedObligationsMet());
|
||||
|
||||
undoRepayment(loanId, repaymentId, todayDate);
|
||||
|
||||
GetLoansLoanIdResponse loanAfterUndo = getLoanDetails(loanId);
|
||||
verifyLoanStatus(loanAfterUndo, status -> status.getActive());
|
||||
|
||||
LocalDate expectedRepaymentDate = Utils.getLocalDateOfTenant().plusMonths(1);
|
||||
validateRepaymentPeriod(loanAfterUndo, 1, expectedRepaymentDate, 1000.0, 0.0, 1000.0);
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.client.feign.tests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class FeignLoanTestBaseSmokeTest extends FeignLoanTestBase {
|
||||
|
||||
@Test
|
||||
void testInfrastructureInitialization() {
|
||||
assertNotNull(accountHelper);
|
||||
assertNotNull(loanHelper);
|
||||
assertNotNull(transactionHelper);
|
||||
assertNotNull(journalHelper);
|
||||
assertNotNull(businessDateHelper);
|
||||
assertNotNull(clientHelper);
|
||||
assertNotNull(getAccounts());
|
||||
assertNotNull(getAccounts().getLoansReceivableAccount());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateClient() {
|
||||
Long clientId = createClient("Test", "User");
|
||||
assertNotNull(clientId);
|
||||
}
|
||||
}
|
||||
+81
-13
@@ -59,6 +59,7 @@ import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuil
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanStatusChecker;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -106,6 +107,12 @@ public class CobPartitioningTest extends BaseLoanIntegrationTest {
|
||||
setProperFinancialActivity(TRANSFER_ACCOUNT);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown() {
|
||||
// Restore business date configuration after each test
|
||||
cleanUpAndRestoreBusinessDate();
|
||||
}
|
||||
|
||||
private static void setProperFinancialActivity(Account transferAccount) {
|
||||
List<GetFinancialActivityAccountsResponse> financialMappings = FINANCIAL_ACTIVITY_ACCOUNT_HELPER.getAllFinancialActivityAccounts();
|
||||
financialMappings.forEach(mapping -> FINANCIAL_ACTIVITY_ACCOUNT_HELPER.deleteFinancialActivityAccount(mapping.getId()));
|
||||
@@ -144,13 +151,16 @@ public class CobPartitioningTest extends BaseLoanIntegrationTest {
|
||||
|
||||
// Force close loans 3, 4, ... , N-3, N-2
|
||||
Collections.sort(loanIds);
|
||||
List<Integer> forelosedLoanIds = new ArrayList<>();
|
||||
final CountDownLatch closeLatch = new CountDownLatch(N - 5);
|
||||
// Warm up (EclipseLink sometimes fails if JPQL cache is not warm up but concurrent queries are executed)
|
||||
LOAN_TRANSACTION_HELPER.forecloseLoan("02 March 2020", loanIds.get(2));
|
||||
forelosedLoanIds.add(loanIds.get(2));
|
||||
for (int i = 3; i < N - 2; i++) {
|
||||
final int idx = i;
|
||||
futures.add(executorService.submit(() -> {
|
||||
LOAN_TRANSACTION_HELPER.forecloseLoan("02 March 2020", loanIds.get(idx));
|
||||
forelosedLoanIds.add(loanIds.get(idx));
|
||||
closeLatch.countDown();
|
||||
}));
|
||||
}
|
||||
@@ -163,24 +173,45 @@ public class CobPartitioningTest extends BaseLoanIntegrationTest {
|
||||
});
|
||||
closeLatch.await();
|
||||
|
||||
// Create list of active (non-foreclosed) loan IDs
|
||||
List<Integer> activeLoanIds = new ArrayList<>(loanIds);
|
||||
activeLoanIds.removeAll(forelosedLoanIds);
|
||||
log.info("Active loan IDs after foreclosure: {}", activeLoanIds);
|
||||
|
||||
// Let's retrieve the partitions
|
||||
List<Map<String, Object>> cobPartitions = CobHelper.getCobPartitions(REQUEST_SPEC, RESPONSE_SPEC, 3, "");
|
||||
log.info("\nLoans created: {},\nRetrieved partitions: {}", loanIds, cobPartitions);
|
||||
Assertions.assertEquals(2, cobPartitions.size());
|
||||
List<Map<String, Object>> allPartitions = CobHelper.getCobPartitions(REQUEST_SPEC, RESPONSE_SPEC, 3, "");
|
||||
log.info("\nLoans created by this test: {}\nAll partitions retrieved: {}", loanIds, allPartitions);
|
||||
|
||||
Assertions.assertEquals(0, cobPartitions.get(0).get("pageNo"));
|
||||
Assertions.assertEquals(loanIds.get(0), cobPartitions.get(0).get("minId"));
|
||||
Assertions.assertEquals(loanIds.get(8), cobPartitions.get(0).get("maxId"));
|
||||
Assertions.assertEquals(3, cobPartitions.get(0).get("count"));
|
||||
// Filter partitions to only include ACTIVE loans created by THIS test
|
||||
// This ensures test isolation - we don't care about leftover loans from other tests
|
||||
List<Map<String, Object>> testLoanPartitions = filterPartitionsForTestLoans(allPartitions, activeLoanIds);
|
||||
log.info("Filtered partitions containing only our active test loans: {}", testLoanPartitions);
|
||||
|
||||
Assertions.assertEquals(1, cobPartitions.get(1).get("pageNo"));
|
||||
Assertions.assertEquals(loanIds.get(9), cobPartitions.get(1).get("minId"));
|
||||
Assertions.assertEquals(loanIds.get(9), cobPartitions.get(1).get("maxId"));
|
||||
Assertions.assertEquals(1, cobPartitions.get(1).get("count"));
|
||||
// Verify partitioning works correctly for our 4 active loans (10 created - 6 foreclosed)
|
||||
// Expected: 2 partitions with page size 3
|
||||
// Partition 0: loans 0, 1, 8 (3 loans)
|
||||
// Partition 1: loan 9 (1 loan)
|
||||
Assertions.assertEquals(2, testLoanPartitions.size(), "Expected 2 partitions for our 4 active test loans");
|
||||
|
||||
// Verify first partition
|
||||
Assertions.assertEquals(0, testLoanPartitions.get(0).get("pageNo"));
|
||||
Assertions.assertEquals(3, testLoanPartitions.get(0).get("count"));
|
||||
Assertions.assertTrue(isLoanIdInRange(loanIds.get(0), testLoanPartitions.get(0)),
|
||||
"First active loan should be in first partition");
|
||||
Assertions.assertTrue(isLoanIdInRange(loanIds.get(1), testLoanPartitions.get(0)),
|
||||
"Second active loan should be in first partition");
|
||||
Assertions.assertTrue(isLoanIdInRange(loanIds.get(8), testLoanPartitions.get(0)),
|
||||
"Ninth active loan should be in first partition");
|
||||
|
||||
// Verify second partition
|
||||
Assertions.assertEquals(1, testLoanPartitions.get(1).get("pageNo"));
|
||||
Assertions.assertEquals(1, testLoanPartitions.get(1).get("count"));
|
||||
Assertions.assertTrue(isLoanIdInRange(loanIds.get(9), testLoanPartitions.get(1)), "Tenth loan should be in second partition");
|
||||
|
||||
executorService.shutdown();
|
||||
} finally {
|
||||
cleanUpAndRestoreBusinessDate();
|
||||
} catch (Exception e) {
|
||||
log.error("Test failed with exception", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,4 +322,41 @@ public class CobPartitioningTest extends BaseLoanIntegrationTest {
|
||||
return collateral;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters partitions to only include those containing loans from the test's loan IDs. This ensures test isolation
|
||||
* by ignoring any leftover loans from previous test runs.
|
||||
*/
|
||||
private List<Map<String, Object>> filterPartitionsForTestLoans(List<Map<String, Object>> allPartitions, List<Integer> testLoanIds) {
|
||||
List<Map<String, Object>> filteredPartitions = new ArrayList<>();
|
||||
|
||||
for (Map<String, Object> partition : allPartitions) {
|
||||
Integer minId = (Integer) partition.get("minId");
|
||||
Integer maxId = (Integer) partition.get("maxId");
|
||||
|
||||
// Check if this partition contains any of our test loan IDs
|
||||
boolean containsTestLoans = testLoanIds.stream().anyMatch(loanId -> loanId >= minId && loanId <= maxId);
|
||||
|
||||
if (containsTestLoans) {
|
||||
// Count how many of OUR loans are in this partition's range
|
||||
long testLoansInPartition = testLoanIds.stream().filter(loanId -> loanId >= minId && loanId <= maxId).count();
|
||||
|
||||
// Create a new partition entry with corrected count
|
||||
Map<String, Object> filteredPartition = new HashMap<>(partition);
|
||||
filteredPartition.put("count", (int) testLoansInPartition);
|
||||
filteredPartitions.add(filteredPartition);
|
||||
}
|
||||
}
|
||||
|
||||
return filteredPartitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a loan ID falls within the min/max range of a partition.
|
||||
*/
|
||||
private boolean isLoanIdInRange(Integer loanId, Map<String, Object> partition) {
|
||||
Integer minId = (Integer) partition.get("minId");
|
||||
Integer maxId = (Integer) partition.get("maxId");
|
||||
return loanId >= minId && loanId <= maxId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.common;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import org.apache.fineract.client.feign.FineractFeignClient;
|
||||
import org.apache.fineract.integrationtests.ConfigProperties;
|
||||
|
||||
public final class FineractFeignClientHelper {
|
||||
|
||||
private static final FineractFeignClient DEFAULT_FINERACT_FEIGN_CLIENT = createNewFineractFeignClient(ConfigProperties.Backend.USERNAME,
|
||||
ConfigProperties.Backend.PASSWORD);
|
||||
|
||||
private FineractFeignClientHelper() {}
|
||||
|
||||
public static FineractFeignClient getFineractFeignClient() {
|
||||
return DEFAULT_FINERACT_FEIGN_CLIENT;
|
||||
}
|
||||
|
||||
public static FineractFeignClient createNewFineractFeignClient(String username, String password) {
|
||||
return createNewFineractFeignClient(username, password, Function.identity()::apply);
|
||||
}
|
||||
|
||||
public static FineractFeignClient createNewFineractFeignClient(String username, String password, boolean debugEnabled) {
|
||||
return createNewFineractFeignClient(username, password, builder -> builder.debug(debugEnabled));
|
||||
}
|
||||
|
||||
public static FineractFeignClient createNewFineractFeignClient(String username, String password,
|
||||
Consumer<FineractFeignClient.Builder> customizer) {
|
||||
String url = System.getProperty("fineract.it.url", buildURI());
|
||||
FineractFeignClient.Builder builder = FineractFeignClient.builder().baseUrl(url).credentials(username, password)
|
||||
.disableSslVerification(true);
|
||||
customizer.accept(builder);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static String buildURI() {
|
||||
return ConfigProperties.Backend.PROTOCOL + "://" + ConfigProperties.Backend.HOST + ":" + ConfigProperties.Backend.PORT
|
||||
+ "/fineract-provider/api";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user