FINERACT-1927: Incorrect exception info in BatchAPI response
This commit is contained in:
+7
-5
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.integrationtests;
|
||||
|
||||
import static org.apache.http.HttpStatus.SC_FORBIDDEN;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
@@ -45,6 +46,7 @@ import org.apache.commons.lang3.RandomUtils;
|
||||
import org.apache.fineract.batch.command.internal.AdjustTransactionCommandStrategy;
|
||||
import org.apache.fineract.batch.command.internal.CreateTransactionLoanCommandStrategy;
|
||||
import org.apache.fineract.batch.command.internal.GetDatatableEntryByAppTableIdAndDataTableIdCommandStrategy;
|
||||
import org.apache.fineract.batch.command.internal.GetTransactionByIdCommandStrategy;
|
||||
import org.apache.fineract.batch.domain.BatchRequest;
|
||||
import org.apache.fineract.batch.domain.BatchResponse;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
@@ -207,7 +209,7 @@ public class BatchApiTest {
|
||||
|
||||
// Asserts that all the transactions have been successfully rolled back
|
||||
Assertions.assertEquals(1, response.size());
|
||||
Assertions.assertEquals((long) 500, (long) response.get(0).getStatusCode(), "Verify Status code 500");
|
||||
Assertions.assertEquals(SC_FORBIDDEN, response.get(0).getStatusCode(), "Verify Status code 500");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1074,7 +1076,7 @@ public class BatchApiTest {
|
||||
* Test for the successful disbursement and get loan. A '200' status code is expected on successful responses.
|
||||
*
|
||||
* @see org.apache.fineract.batch.command.internal.DisburseLoanCommandStrategy
|
||||
* @see org.apache.fineract.batch.command.internal.GetTransactionByIdCommandStrategy
|
||||
* @see GetTransactionByIdCommandStrategy
|
||||
*/
|
||||
@Test
|
||||
public void shouldReturnOkStatusOnSuccessfulDisbursementAndGetTransaction() {
|
||||
@@ -1432,7 +1434,7 @@ public class BatchApiTest {
|
||||
assertNotNull(datatableEntryResourceId, "ERROR IN CREATING THE ENTITY DATATABLE RECORD");
|
||||
|
||||
// Create datatable entry batch request
|
||||
final BatchRequest createDatatableEntryRequest = BatchHelper.createDatatableEntryRequest(loanId, datatableName,
|
||||
final BatchRequest createDatatableEntryRequest = BatchHelper.createDatatableEntryRequest(loanId.toString(), datatableName,
|
||||
Arrays.asList(columnName1, columnName2));
|
||||
|
||||
// Update datatable entry batch request
|
||||
@@ -2166,7 +2168,7 @@ public class BatchApiTest {
|
||||
Assertions.assertEquals(2L, updateResponse.getRequestId());
|
||||
Assertions.assertEquals(HttpStatus.SC_BAD_REQUEST, updateResponse.getStatusCode(),
|
||||
"Verify Status Code 400 for update datatable entry");
|
||||
MatcherAssert.assertThat(updateResponse.getBody(), containsString("No results for path"));
|
||||
MatcherAssert.assertThat(updateResponse.getBody(), containsString("The referenced JSON path is invalid"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2211,7 +2213,7 @@ public class BatchApiTest {
|
||||
assertNotNull(datatableEntryResourceId, "ERROR IN CREATING THE ENTITY DATATABLE RECORD");
|
||||
|
||||
// Create datatable entry batch request
|
||||
final BatchRequest createDatatableEntryRequest = BatchHelper.createDatatableEntryRequest(loanId, datatableName,
|
||||
final BatchRequest createDatatableEntryRequest = BatchHelper.createDatatableEntryRequest(loanId.toString(), datatableName,
|
||||
Arrays.asList(columnName1, columnName2));
|
||||
|
||||
// Get datatable entries batch request
|
||||
|
||||
+2
-4
@@ -2655,8 +2655,7 @@ public class ClientSavingsIntegrationTest {
|
||||
this.savingsAccountHelper.addChargesForSavings(savingsId, chargeIdOne, false, BigDecimal.valueOf(withdrawalChargeOne));
|
||||
|
||||
Integer withdrawTransactionIdOne = (Integer) this.savingsAccountHelper.withdrawalFromSavingsAccountWithPaymentType(savingsId,
|
||||
withdrawalAmountOne, SavingsAccountHelper.TRANSACTION_DATE, paymentTypeIdOne.toString(),
|
||||
CommonConstants.RESPONSE_RESOURCE_ID);
|
||||
withdrawalAmountOne, SavingsAccountHelper.TRANSACTION_DATE, paymentTypeIdOne, CommonConstants.RESPONSE_RESOURCE_ID);
|
||||
|
||||
Float balance = Float.parseFloat("8990");
|
||||
// Withdraw charge from paymentType 1 is 10 So balance should be 10,000(deposit)-1000(wd)-"10(charge)" = 8990
|
||||
@@ -2678,8 +2677,7 @@ public class ClientSavingsIntegrationTest {
|
||||
this.savingsAccountHelper.addChargesForSavings(savingsId, chargeIdTwo, false, BigDecimal.valueOf(withdrawalChargeTwo));
|
||||
|
||||
Integer withdrawTransactionIdTwo = (Integer) this.savingsAccountHelper.withdrawalFromSavingsAccountWithPaymentType(savingsId,
|
||||
withdrawalAmountTwo, SavingsAccountHelper.TRANSACTION_DATE, paymentTypeIdTwo.toString(),
|
||||
CommonConstants.RESPONSE_RESOURCE_ID);
|
||||
withdrawalAmountTwo, SavingsAccountHelper.TRANSACTION_DATE, paymentTypeIdTwo, CommonConstants.RESPONSE_RESOURCE_ID);
|
||||
|
||||
Float balanceAfterChargeTwo = Float.parseFloat("6970");
|
||||
// Withdraw charge from paymentType 2 is 20 So balance should be 8990(balance)-2000(wd)-"20(charge)" = 6970
|
||||
|
||||
+230
-13
@@ -18,21 +18,43 @@
|
||||
*/
|
||||
package org.apache.fineract.integrationtests;
|
||||
|
||||
import static org.apache.fineract.integrationtests.common.savings.SavingsAccountHelper.PAYMENT_TYPE_ID;
|
||||
import static org.apache.fineract.integrationtests.common.system.DatatableHelper.addDatatableColumn;
|
||||
import static org.apache.http.HttpStatus.SC_CONFLICT;
|
||||
import static org.apache.http.HttpStatus.SC_FORBIDDEN;
|
||||
import static org.apache.http.HttpStatus.SC_OK;
|
||||
import static org.hamcrest.Matchers.anyOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
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 com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.google.gson.Gson;
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.builder.ResponseSpecBuilder;
|
||||
import io.restassured.http.ContentType;
|
||||
import io.restassured.path.json.JsonPath;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import io.restassured.specification.ResponseSpecification;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.fineract.batch.domain.BatchRequest;
|
||||
import org.apache.fineract.batch.domain.BatchResponse;
|
||||
import org.apache.fineract.batch.domain.Header;
|
||||
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.integrationtests.common.BatchHelper;
|
||||
import org.apache.fineract.integrationtests.common.BusinessDateHelper;
|
||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||
import org.apache.fineract.integrationtests.common.CommonConstants;
|
||||
@@ -41,14 +63,19 @@ import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.apache.fineract.integrationtests.common.savings.SavingsAccountHelper;
|
||||
import org.apache.fineract.integrationtests.common.savings.SavingsProductHelper;
|
||||
import org.apache.fineract.integrationtests.common.savings.SavingsStatusChecker;
|
||||
import org.apache.fineract.integrationtests.common.savings.SavingsTransactionData;
|
||||
import org.apache.fineract.integrationtests.common.system.DatatableHelper;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@SuppressWarnings({ "rawtypes" })
|
||||
public class SavingsAccountTransactionTest {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SavingsAccountTransactionTest.class);
|
||||
|
||||
public static final String ACCOUNT_TYPE_INDIVIDUAL = "INDIVIDUAL";
|
||||
public static final String DEFAULT_DATE_FORMAT = "dd MMMM yyyy";
|
||||
final String startDateString = "03 June 2023";
|
||||
@@ -56,23 +83,27 @@ public class SavingsAccountTransactionTest {
|
||||
final String withdrawDateString = "10 June 2023";
|
||||
|
||||
private ResponseSpecification responseSpec;
|
||||
private ResponseSpecification concurrentResponseSpec;
|
||||
private RequestSpecification requestSpec;
|
||||
private SavingsProductHelper savingsProductHelper;
|
||||
private SavingsAccountHelper savingsAccountHelper;
|
||||
private DatatableHelper datatableHelper;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
Utils.initializeRESTAssured();
|
||||
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
|
||||
this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
|
||||
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
|
||||
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(SC_OK).build();
|
||||
this.concurrentResponseSpec = new ResponseSpecBuilder().expectStatusCode(anyOf(is(SC_OK), is(SC_CONFLICT))).build();
|
||||
this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec);
|
||||
this.savingsProductHelper = new SavingsProductHelper();
|
||||
this.datatableHelper = new DatatableHelper(this.requestSpec, this.responseSpec);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifySavingsTransactionSubmittedOnDateAndTransactionDate() throws JsonProcessingException {
|
||||
LocalDate today = LocalDate.now(ZoneId.systemDefault());
|
||||
LocalDate today = Utils.getLocalDateOfTenant();
|
||||
try {
|
||||
enableBusinessDate(requestSpec, responseSpec, true);
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, today);
|
||||
@@ -81,17 +112,106 @@ public class SavingsAccountTransactionTest {
|
||||
LocalDate withdrawDate = Utils.getDateAsLocalDate(withdrawDateString);
|
||||
|
||||
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, startDateString);
|
||||
Assertions.assertNotNull(clientID);
|
||||
assertNotNull(clientID);
|
||||
|
||||
final Integer savingsId = createSavingsAccountDailyPosting(clientID, startDateString);
|
||||
Assertions.assertNotNull(savingsId);
|
||||
assertNotNull(savingsId);
|
||||
|
||||
performSavingsTransaction(savingsId, "100", depositDate, true);
|
||||
performSavingsTransaction(savingsId, "50", withdrawDate, false);
|
||||
} finally {
|
||||
enableBusinessDate(requestSpec, responseSpec, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConcurrentSavingsTransactions() {
|
||||
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||
|
||||
final Integer savingsProductId = createSavingsProductDailyPosting();
|
||||
assertNotNull(savingsProductId);
|
||||
|
||||
final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(clientID, savingsProductId, ACCOUNT_TYPE_INDIVIDUAL);
|
||||
this.savingsAccountHelper.approveSavings(savingsId);
|
||||
HashMap savingsStatusHashMap = this.savingsAccountHelper.activateSavings(savingsId);
|
||||
SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap);
|
||||
|
||||
SavingsAccountHelper concurrentHelper = new SavingsAccountHelper(requestSpec, concurrentResponseSpec);
|
||||
String transactionDate = SavingsAccountHelper.TRANSACTION_DATE;
|
||||
String transactionAmount = "10";
|
||||
ExecutorService executor = Executors.newFixedThreadPool(30);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
log.info("Starting concurrent transaction number {}", i);
|
||||
SavingsTransactionData transactionData = SavingsTransactionData.builder().transactionDate(transactionDate)
|
||||
.transactionAmount(transactionAmount).paymentTypeId(PAYMENT_TYPE_ID).note("note_" + i).build();
|
||||
Runnable worker = new TransactionExecutor(concurrentHelper, savingsId, transactionData);
|
||||
executor.execute(worker);
|
||||
}
|
||||
|
||||
executor.shutdown();
|
||||
// Wait until all threads are finish
|
||||
while (!executor.isTerminated()) {
|
||||
|
||||
}
|
||||
log.info("\nFinished all threads");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConcurrentSavingsBatchTransactions() {
|
||||
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||
|
||||
final Integer savingsProductId = createSavingsProductDailyPosting();
|
||||
assertNotNull(savingsProductId);
|
||||
|
||||
final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplication(clientID, savingsProductId, ACCOUNT_TYPE_INDIVIDUAL);
|
||||
this.savingsAccountHelper.approveSavings(savingsId);
|
||||
HashMap savingsStatusHashMap = this.savingsAccountHelper.activateSavings(savingsId);
|
||||
SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap);
|
||||
|
||||
// creating datatable for client entity
|
||||
final HashMap<String, Object> columnMap = new HashMap<>();
|
||||
String datatableName = Utils.uniqueRandomStringGenerator("savings_transaction" + "_", 5).toLowerCase();
|
||||
columnMap.put("datatableName", datatableName);
|
||||
columnMap.put("apptableName", "m_savings_account_transaction");
|
||||
columnMap.put("multiRow", false);
|
||||
String string1 = "string1";
|
||||
String string2 = "string2";
|
||||
List<String> columnNames = List.of(string1, string2);
|
||||
|
||||
final List<HashMap<String, Object>> datatableColumnsList = new ArrayList<>();
|
||||
addDatatableColumn(datatableColumnsList, string1, "String", false, 10, null);
|
||||
addDatatableColumn(datatableColumnsList, string2, "String", true, 12, null);
|
||||
columnMap.put("columns", datatableColumnsList);
|
||||
String datatableJson = new Gson().toJson(columnMap);
|
||||
this.datatableHelper.createDatatable(datatableJson, "");
|
||||
|
||||
SavingsAccountHelper batchWithTransactionHelper = new SavingsAccountHelper(requestSpec, concurrentResponseSpec);
|
||||
SavingsAccountHelper batchWithoutTransactionHelper = new SavingsAccountHelper(requestSpec,
|
||||
new ResponseSpecBuilder().expectStatusCode(anyOf(is(SC_OK), is(SC_CONFLICT), is(SC_FORBIDDEN))).build());
|
||||
String transactionDate = SavingsAccountHelper.TRANSACTION_DATE;
|
||||
String transactionAmount = "10";
|
||||
ExecutorService executor = Executors.newFixedThreadPool(30);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
log.info("Starting concurrent transaction number {}", i);
|
||||
SavingsTransactionData transactionData = SavingsTransactionData.builder().transactionDate(transactionDate)
|
||||
.transactionAmount(transactionAmount).paymentTypeId(PAYMENT_TYPE_ID).note("note_" + i).build();
|
||||
Runnable workerWithTransaction = new TransactionExecutor(batchWithTransactionHelper, savingsId, transactionData, true,
|
||||
datatableName, columnNames);
|
||||
executor.execute(workerWithTransaction);
|
||||
Runnable workerWithoutTransaction = new TransactionExecutor(batchWithoutTransactionHelper, savingsId, transactionData, false,
|
||||
datatableName, columnNames);
|
||||
executor.execute(workerWithoutTransaction);
|
||||
}
|
||||
|
||||
executor.shutdown();
|
||||
// Wait until all threads are finish
|
||||
while (!executor.isTerminated()) {
|
||||
|
||||
}
|
||||
this.datatableHelper.deleteDatatable(datatableName);
|
||||
log.info("\nFinished all threads");
|
||||
}
|
||||
|
||||
private void enableBusinessDate(RequestSpecification requestSpec, ResponseSpecification responseSpec, boolean enable) {
|
||||
@@ -106,17 +226,17 @@ public class SavingsAccountTransactionTest {
|
||||
: (Integer) this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, amount, withdrawDateString,
|
||||
CommonConstants.RESPONSE_RESOURCE_ID);
|
||||
|
||||
Assertions.assertNotNull(transactionId);
|
||||
assertNotNull(transactionId);
|
||||
|
||||
HashMap transaction = savingsAccountHelper.getSavingsTransaction(savingsId, transactionId);
|
||||
Assertions.assertNotNull(transaction);
|
||||
assertNotNull(transaction);
|
||||
|
||||
assertEquals(transactionId, (Integer) transaction.get("id"), "Check Savings " + transactionType + " Transaction");
|
||||
LocalDate transactionDateFromResponse = extractLocalDate(transaction, "date");
|
||||
assertTrue(transactionDate.compareTo(transactionDateFromResponse) == 0,
|
||||
assertTrue(DateUtils.isEqual(transactionDate, transactionDateFromResponse),
|
||||
"Transaction Date check for Savings " + transactionType + " Transaction");
|
||||
LocalDate submittedOnDate = extractLocalDate(transaction, "submittedOnDate");
|
||||
assertTrue(LocalDate.now(ZoneId.systemDefault()).compareTo(submittedOnDate) == 0,
|
||||
assertTrue(DateUtils.isEqual(submittedOnDate, Utils.getLocalDateOfTenant()),
|
||||
"Submitted On Date check for Savings " + transactionType + " Transaction");
|
||||
}
|
||||
|
||||
@@ -129,10 +249,10 @@ public class SavingsAccountTransactionTest {
|
||||
|
||||
private Integer createSavingsAccountDailyPosting(final Integer clientID, final String startDate) {
|
||||
final Integer savingsProductID = createSavingsProductDailyPosting();
|
||||
Assertions.assertNotNull(savingsProductID);
|
||||
assertNotNull(savingsProductID);
|
||||
final Integer savingsId = this.savingsAccountHelper.applyForSavingsApplicationOnDate(clientID, savingsProductID,
|
||||
ACCOUNT_TYPE_INDIVIDUAL, startDate);
|
||||
Assertions.assertNotNull(savingsId);
|
||||
assertNotNull(savingsId);
|
||||
HashMap savingsStatusHashMap = this.savingsAccountHelper.approveSavingsOnDate(savingsId, startDate);
|
||||
SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap);
|
||||
savingsStatusHashMap = this.savingsAccountHelper.activateSavingsAccount(savingsId, startDate);
|
||||
@@ -146,11 +266,108 @@ public class SavingsAccountTransactionTest {
|
||||
return SavingsProductHelper.createSavingsProduct(savingsProductJSON, requestSpec, responseSpec);
|
||||
}
|
||||
|
||||
public static class TransactionExecutor implements Runnable {
|
||||
|
||||
private SavingsAccountHelper savingsHelper;
|
||||
private final Integer savingsId;
|
||||
SavingsTransactionData transactionData;
|
||||
boolean batch;
|
||||
boolean enclosingTransaction;
|
||||
String datatableName;
|
||||
List<String> columnNames;
|
||||
|
||||
private TransactionExecutor(SavingsAccountHelper savingsHelper, Integer savingsId, SavingsTransactionData transactionData,
|
||||
boolean batch, boolean enclosingTransaction, String datatableName, List<String> columnNames) {
|
||||
this.savingsId = savingsId;
|
||||
this.savingsHelper = savingsHelper;
|
||||
this.transactionData = transactionData;
|
||||
this.batch = batch;
|
||||
this.enclosingTransaction = enclosingTransaction;
|
||||
this.datatableName = datatableName;
|
||||
this.columnNames = columnNames;
|
||||
}
|
||||
|
||||
TransactionExecutor(SavingsAccountHelper savingsAccountHelper, Integer savingsId, SavingsTransactionData transactionData) {
|
||||
this(savingsAccountHelper, savingsId, transactionData, false, false, null, null);
|
||||
}
|
||||
|
||||
TransactionExecutor(SavingsAccountHelper batchHelper, Integer savingsId, SavingsTransactionData transactionData,
|
||||
boolean enclosingTransaction, String datatableName, List<String> columnNames) {
|
||||
this(batchHelper, savingsId, transactionData, true, enclosingTransaction, datatableName, columnNames);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
log.info("Details of passed concurrent transaction, details (date, amount, note, savingsId) are {},{},{},{}",
|
||||
transactionData.getTransactionDate(), transactionData.getTransactionAmount(), transactionData.getNote(), savingsId);
|
||||
if (batch) {
|
||||
final BatchRequest depositRequest = BatchHelper.depositSavingAccount(1L, savingsId.longValue(), transactionData);
|
||||
Set<Header> headers = Optional.ofNullable(depositRequest.getHeaders()).orElse(new HashSet<>(1));
|
||||
headers.add(new Header("Idempotency-Key", UUID.randomUUID().toString()));
|
||||
depositRequest.setHeaders(headers);
|
||||
BatchRequest addEntryRequest = BatchHelper.createDatatableEntryRequest("$.resourceId", datatableName, columnNames);
|
||||
addEntryRequest.setReference(1L);
|
||||
BatchRequest deleteEntryRequest = BatchHelper.deleteDatatableEntryRequest("$.transactionId", datatableName, null);
|
||||
final BatchRequest withdrawRequest = BatchHelper.withdrawSavingAccount(2L, savingsId.longValue(), transactionData);
|
||||
headers = Optional.ofNullable(withdrawRequest.getHeaders()).orElse(new HashSet<>(1));
|
||||
headers.add(new Header("Idempotency-Key", UUID.randomUUID().toString()));
|
||||
withdrawRequest.setHeaders(headers);
|
||||
String json = BatchHelper.toJsonString(Arrays.asList(depositRequest, addEntryRequest, deleteEntryRequest, withdrawRequest));
|
||||
RequestSpecification requestSpec = savingsHelper.getRequestSpec();
|
||||
ResponseSpecification responseSpec = savingsHelper.getResponseSpec();
|
||||
final List<BatchResponse> responses = enclosingTransaction
|
||||
? BatchHelper.postBatchRequestsWithEnclosingTransaction(requestSpec, responseSpec, json)
|
||||
: BatchHelper.postBatchRequestsWithoutEnclosingTransaction(requestSpec, responseSpec, json);
|
||||
assertNotNull(responses);
|
||||
if (enclosingTransaction) {
|
||||
Integer statusCode1 = responses.get(0).getStatusCode();
|
||||
assertNotNull(statusCode1);
|
||||
assertTrue(SC_OK == statusCode1 || SC_CONFLICT == statusCode1);
|
||||
if (SC_OK == statusCode1) {
|
||||
assertEquals(4, responses.size());
|
||||
Integer statusCode4 = responses.get(3).getStatusCode();
|
||||
assertNotNull(statusCode4);
|
||||
assertEquals(SC_OK, statusCode4);
|
||||
} else {
|
||||
assertEquals(1, responses.size());
|
||||
}
|
||||
} else {
|
||||
assertEquals(4, responses.size());
|
||||
Integer statusCode1 = responses.get(0).getStatusCode();
|
||||
assertNotNull(statusCode1);
|
||||
assertTrue(SC_OK == statusCode1 || SC_CONFLICT == statusCode1);
|
||||
Integer statusCode4 = responses.get(3).getStatusCode();
|
||||
assertNotNull(statusCode4);
|
||||
assertTrue(SC_OK == statusCode1 ? (SC_OK == statusCode4 || SC_CONFLICT == statusCode4) : SC_FORBIDDEN == statusCode4);
|
||||
}
|
||||
} else {
|
||||
String json = transactionData.getJson();
|
||||
String response = (String) this.savingsHelper.depositToSavingsAccount(savingsId, json, null);
|
||||
boolean success = checkConcurrentResponse(response);
|
||||
if (success) {
|
||||
response = (String) this.savingsHelper.withdrawalFromSavingsAccount(savingsId, json, null);
|
||||
checkConcurrentResponse(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean checkConcurrentResponse(String response) {
|
||||
assertNotNull(response);
|
||||
JsonPath res = JsonPath.from(response);
|
||||
String statusCode = (String) res.get("httpStatusCode");
|
||||
if (statusCode == null) {
|
||||
assertNotNull(res.get(CommonConstants.RESPONSE_RESOURCE_ID));
|
||||
return true;
|
||||
}
|
||||
assertEquals(String.valueOf(SC_CONFLICT), statusCode);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset configuration fields
|
||||
@AfterEach
|
||||
public void tearDown() {
|
||||
GlobalConfigurationHelper.resetAllDefaultGlobalConfigurations(this.requestSpec, this.responseSpec);
|
||||
GlobalConfigurationHelper.verifyAllDefaultGlobalConfigurations(this.requestSpec, this.responseSpec);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+59
-31
@@ -34,8 +34,11 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.fineract.batch.command.internal.CreateTransactionLoanCommandStrategy;
|
||||
import org.apache.fineract.batch.command.internal.GetTransactionByExternalIdCommandStrategy;
|
||||
import org.apache.fineract.batch.command.internal.GetTransactionByIdCommandStrategy;
|
||||
import org.apache.fineract.batch.domain.BatchRequest;
|
||||
import org.apache.fineract.batch.domain.BatchResponse;
|
||||
import org.apache.fineract.integrationtests.common.savings.SavingsTransactionData;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -1018,8 +1021,7 @@ public final class BatchHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a {@link org.apache.fineract.batch.command.internal.GetTransactionByIdCommandStrategy}
|
||||
* request with given requestId and reference.
|
||||
* Creates and returns a {@link GetTransactionByIdCommandStrategy} request with given requestId and reference.
|
||||
*
|
||||
* @param requestId
|
||||
* the request id
|
||||
@@ -1049,9 +1051,8 @@ public final class BatchHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a
|
||||
* {@link org.apache.fineract.batch.command.internal.GetTransactionByExternalIdCommandStrategy} request with given
|
||||
* requestId and reference.
|
||||
* Creates and returns a {@link GetTransactionByExternalIdCommandStrategy} request with given requestId and
|
||||
* reference.
|
||||
*
|
||||
* @param requestId
|
||||
* the request id
|
||||
@@ -1247,17 +1248,18 @@ public final class BatchHelper {
|
||||
/**
|
||||
* Creates and returns a batch request to create datatable entry.
|
||||
*
|
||||
* @param loanId
|
||||
* the loan id
|
||||
* @param entityId
|
||||
* the entity id
|
||||
* @param datatableName
|
||||
* the name of datatable
|
||||
* @param columnNames
|
||||
* the column names
|
||||
* @return the {@link BatchRequest}
|
||||
*/
|
||||
public static BatchRequest createDatatableEntryRequest(final Long loanId, final String datatableName, final List<String> columnNames) {
|
||||
public static BatchRequest createDatatableEntryRequest(final String entityId, final String datatableName,
|
||||
final List<String> columnNames) {
|
||||
final BatchRequest br = new BatchRequest();
|
||||
final String relativeUrl = String.format("v1/datatables/%s/%s", datatableName, loanId);
|
||||
final String relativeUrl = String.format("v1/datatables/%s/%s", datatableName, entityId);
|
||||
final Map<String, Object> datatableEntryMap = new HashMap<>();
|
||||
datatableEntryMap.putAll(columnNames.stream().collect(Collectors.toMap(v -> v, v -> Utils.randomStringGenerator("VAL_", 3))));
|
||||
final String datatableEntryRequestJsonString = new Gson().toJson(datatableEntryMap);
|
||||
@@ -1302,6 +1304,18 @@ public final class BatchHelper {
|
||||
return br;
|
||||
}
|
||||
|
||||
public static BatchRequest deleteDatatableEntryRequest(final String entityId, final String datatableName,
|
||||
final String datatableEntryId) {
|
||||
final BatchRequest br = new BatchRequest();
|
||||
final String relativeUrl = datatableEntryId == null ? String.format("v1/datatables/%s/%s", datatableName, entityId)
|
||||
: String.format("v1/datatables/%s/%s/%s", datatableName, entityId, datatableEntryId);
|
||||
br.setRequestId(4570L);
|
||||
br.setReference(4569L);
|
||||
br.setRelativeUrl(relativeUrl);
|
||||
br.setMethod(HttpMethod.DELETE);
|
||||
return br;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a batch request to create an adjust transaction request.
|
||||
*
|
||||
@@ -1461,7 +1475,6 @@ public final class BatchHelper {
|
||||
*
|
||||
* @param datatableName
|
||||
* @param resourceId
|
||||
* @param subResourceId
|
||||
* @param columnName
|
||||
* @param columnValue
|
||||
* @return
|
||||
@@ -1544,51 +1557,66 @@ public final class BatchHelper {
|
||||
* Creates and returns a {@link org.apache.fineract.batch.command.internal.SavingsAccountTransactionCommandStrategy}
|
||||
* request with given request ID.
|
||||
*
|
||||
*
|
||||
* @param requestId
|
||||
* the request ID
|
||||
* @param reference
|
||||
* teh reference
|
||||
* the reference
|
||||
* @return BatchRequest the created {@link BatchRequest}
|
||||
*/
|
||||
public static BatchRequest depositSavingAccount(final Long requestId, final Long reference) {
|
||||
final BatchRequest br = new BatchRequest();
|
||||
|
||||
br.setRequestId(requestId);
|
||||
br.setReference(reference);
|
||||
br.setRelativeUrl("v1/savingsaccounts/$.id/transactions?command=deposit");
|
||||
br.setMethod(HttpMethod.POST);
|
||||
final LocalDate transactionDate = LocalDate.now(ZoneId.systemDefault());
|
||||
final String transactionDateString = transactionDate.format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
|
||||
br.setBody(String.format("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", "
|
||||
+ "\"transactionDate\": \"%s\", \"transactionAmount\": \"100\", \"paymentTypeId\": \"1\"}", transactionDateString));
|
||||
|
||||
return br;
|
||||
String json = String.format("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", "
|
||||
+ "\"transactionDate\": \"%s\", \"transactionAmount\": \"100\", \"paymentTypeId\": \"1\"}", transactionDateString);
|
||||
return commandSavingAccount(requestId, null, reference, json, "deposit");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a {@link org.apache.fineract.batch.command.internal.SavingsAccountTransactionCommandStrategy}
|
||||
* request with given request ID.
|
||||
*
|
||||
*
|
||||
* @param requestId
|
||||
* the request ID
|
||||
* @param reference
|
||||
* teh reference
|
||||
* the reference
|
||||
* @return BatchRequest the created {@link BatchRequest}
|
||||
*/
|
||||
public static BatchRequest withdrawSavingAccount(final Long requestId, final Long reference) {
|
||||
final LocalDate transactionDate = LocalDate.now(ZoneId.systemDefault());
|
||||
final String transactionDateString = transactionDate.format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
|
||||
String json = String.format("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", "
|
||||
+ "\"transactionDate\": \"%s\", \"transactionAmount\": \"80\", \"paymentTypeId\": \"1\"}", transactionDateString);
|
||||
return commandSavingAccount(requestId, null, reference, json, "withdrawal");
|
||||
}
|
||||
|
||||
public static BatchRequest depositSavingAccount(final Long requestId, final Long savingsId, SavingsTransactionData transactionData) {
|
||||
return commandSavingAccount(requestId, savingsId, transactionData, "deposit");
|
||||
}
|
||||
|
||||
public static BatchRequest withdrawSavingAccount(final Long requestId, final Long savingsId, SavingsTransactionData transactionData) {
|
||||
return commandSavingAccount(requestId, savingsId, transactionData, "withdrawal");
|
||||
}
|
||||
|
||||
public static BatchRequest commandSavingAccount(Long requestId, Long savingsId, SavingsTransactionData transactionData,
|
||||
String command) {
|
||||
String json = transactionData.getJson();
|
||||
return commandSavingAccount(requestId, savingsId, null, json, command);
|
||||
}
|
||||
|
||||
public static BatchRequest commandSavingAccount(Long requestId, Long savingsId, Long reference, String body, String command) {
|
||||
final BatchRequest br = new BatchRequest();
|
||||
|
||||
br.setRequestId(requestId);
|
||||
br.setReference(reference);
|
||||
br.setRelativeUrl("v1/savingsaccounts/$.id/transactions?command=withdrawal");
|
||||
String id;
|
||||
if (reference != null) {
|
||||
br.setReference(reference);
|
||||
id = "$.id";
|
||||
} else {
|
||||
id = savingsId.toString();
|
||||
}
|
||||
br.setRelativeUrl("v1/savingsaccounts/" + id + "/transactions?command=" + command);
|
||||
br.setMethod(HttpMethod.POST);
|
||||
final LocalDate transactionDate = LocalDate.now(ZoneId.systemDefault());
|
||||
final String transactionDateString = transactionDate.format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
|
||||
br.setBody(String.format("{\"locale\": \"en\", \"dateFormat\": \"dd MMMM yyyy\", "
|
||||
+ "\"transactionDate\": \"%s\", \"transactionAmount\": \"80\", \"paymentTypeId\": \"1\"}", transactionDateString));
|
||||
|
||||
br.setBody(body);
|
||||
return br;
|
||||
}
|
||||
|
||||
|
||||
+32
-46
@@ -97,7 +97,7 @@ public class SavingsAccountHelper extends IntegrationTest {
|
||||
public static final String TRANSACTION_DATE_PLUS_ONE = "02 March 2013";
|
||||
public static final String LAST_TRANSACTION_DATE = "01 March 2013";
|
||||
public static final String ACCOUNT_TYPE_INDIVIDUAL = "INDIVIDUAL";
|
||||
public static final Integer PAYMENT_TYPE_ID = 1;
|
||||
public static final Long PAYMENT_TYPE_ID = 1L;
|
||||
|
||||
public static final String DATE_TIME_FORMAT = "dd MMMM yyyy HH:mm";
|
||||
private static final Boolean IS_BLOCK = false;
|
||||
@@ -107,6 +107,14 @@ public class SavingsAccountHelper extends IntegrationTest {
|
||||
this.responseSpec = responseSpec;
|
||||
}
|
||||
|
||||
public RequestSpecification getRequestSpec() {
|
||||
return requestSpec;
|
||||
}
|
||||
|
||||
public ResponseSpecification getResponseSpec() {
|
||||
return responseSpec;
|
||||
}
|
||||
|
||||
public static String getFutureDate() {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(CommonConstants.DATE_FORMAT, Locale.US);
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
@@ -255,21 +263,29 @@ public class SavingsAccountHelper extends IntegrationTest {
|
||||
|
||||
public Object depositToSavingsAccount(final Integer savingsID, final String amount, String date, String jsonAttributeToGetback) {
|
||||
LOG.info("--------------------------------- SAVINGS TRANSACTION DEPOSIT --------------------------------");
|
||||
return performSavingActions(createSavingsTransactionURL(DEPOSIT_SAVINGS_COMMAND, savingsID),
|
||||
getSavingsTransactionJSON(amount, date), jsonAttributeToGetback);
|
||||
return depositToSavingsAccount(savingsID, getSavingsTransactionJSON(amount, date), jsonAttributeToGetback);
|
||||
}
|
||||
|
||||
public Object depositToSavingsAccount(final Integer savingsID, final String jsonBody, String jsonAttributeToGetback) {
|
||||
LOG.info("--------------------------------- SAVINGS TRANSACTION DEPOSIT --------------------------------");
|
||||
return performSavingActions(createSavingsTransactionURL(DEPOSIT_SAVINGS_COMMAND, savingsID), jsonBody, jsonAttributeToGetback);
|
||||
}
|
||||
|
||||
public Object withdrawalFromSavingsAccount(final Integer savingsId, final String amount, String date, String jsonAttributeToGetback) {
|
||||
LOG.info("\n--------------------------------- SAVINGS TRANSACTION WITHDRAWAL --------------------------------");
|
||||
return performSavingActions(createSavingsTransactionURL(WITHDRAW_SAVINGS_COMMAND, savingsId),
|
||||
getSavingsTransactionJSON(amount, date), jsonAttributeToGetback);
|
||||
return withdrawalFromSavingsAccount(savingsId, getSavingsTransactionJSON(amount, date), jsonAttributeToGetback);
|
||||
}
|
||||
|
||||
public Object withdrawalFromSavingsAccountWithPaymentType(final Integer savingsId, final String amount, String date, String paymentType,
|
||||
public Object withdrawalFromSavingsAccountWithPaymentType(final Integer savingsId, final String amount, String date, Long paymentTypeId,
|
||||
String jsonAttributeToGetback) {
|
||||
LOG.info("\n--------------------------------- SAVINGS TRANSACTION WITHDRAWAL WITH PAYMENT TYPE--------------------------------");
|
||||
return performSavingActions(createSavingsTransactionURL(WITHDRAW_SAVINGS_COMMAND, savingsId),
|
||||
getSavingsTransactionPaymentTypeJSON(amount, date, paymentType), jsonAttributeToGetback);
|
||||
return withdrawalFromSavingsAccount(savingsId, getSavingsTransactionPaymentTypeJSON(amount, date, paymentTypeId),
|
||||
jsonAttributeToGetback);
|
||||
}
|
||||
|
||||
public Object withdrawalFromSavingsAccount(final Integer savingsId, final String jsonBody, String jsonAttributeToGetback) {
|
||||
LOG.info("\n--------------------------------- SAVINGS TRANSACTION WITHDRAWAL --------------------------------");
|
||||
return performSavingActions(createSavingsTransactionURL(WITHDRAW_SAVINGS_COMMAND, savingsId), jsonBody, jsonAttributeToGetback);
|
||||
}
|
||||
|
||||
public Object payChargeToSavingsAccount(final Integer savingsID, final Integer chargeId, final String amount, String date,
|
||||
@@ -473,52 +489,22 @@ public class SavingsAccountHelper extends IntegrationTest {
|
||||
}
|
||||
|
||||
private String getSavingsTransactionJSON(final String amount, final String transactionDate) {
|
||||
final HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("locale", CommonConstants.LOCALE);
|
||||
map.put("dateFormat", CommonConstants.DATE_FORMAT);
|
||||
map.put("transactionDate", transactionDate);
|
||||
map.put("transactionAmount", amount);
|
||||
map.put("paymentTypeId", PAYMENT_TYPE_ID);
|
||||
String savingsAccountWithdrawalJson = new Gson().toJson(map);
|
||||
LOG.info(savingsAccountWithdrawalJson);
|
||||
return savingsAccountWithdrawalJson;
|
||||
return SavingsTransactionData.builder().transactionDate(transactionDate).transactionAmount(amount).paymentTypeId(PAYMENT_TYPE_ID)
|
||||
.build().getJson();
|
||||
}
|
||||
|
||||
private String getSavingsTransactionJSON(final String amount, final String transactionDate, final boolean isBulk) {
|
||||
final HashMap<String, String> map = new HashMap<>();
|
||||
map.put("locale", CommonConstants.LOCALE);
|
||||
map.put("dateFormat", CommonConstants.DATE_FORMAT);
|
||||
map.put("transactionDate", transactionDate);
|
||||
map.put("transactionAmount", amount);
|
||||
map.put("isBulk", String.valueOf(isBulk));
|
||||
String savingsAccountWithdrawalJson = new Gson().toJson(map);
|
||||
LOG.info(savingsAccountWithdrawalJson);
|
||||
return savingsAccountWithdrawalJson;
|
||||
return SavingsTransactionData.builder().transactionDate(transactionDate).transactionAmount(amount).isBulk(isBulk).build().getJson();
|
||||
}
|
||||
|
||||
private String getLienSavingsTransactionJSON(final String amount, final String transactionDate, final Boolean lienAllowed) {
|
||||
final HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("locale", CommonConstants.LOCALE);
|
||||
map.put("dateFormat", CommonConstants.DATE_FORMAT);
|
||||
map.put("transactionDate", transactionDate);
|
||||
map.put("transactionAmount", amount);
|
||||
map.put("lienAllowed", lienAllowed);
|
||||
map.put("reasonForBlock", "unUsualActivity");
|
||||
String savingsAccountWithdrawalJson = new Gson().toJson(map);
|
||||
LOG.info(savingsAccountWithdrawalJson);
|
||||
return savingsAccountWithdrawalJson;
|
||||
return SavingsTransactionData.builder().transactionDate(transactionDate).transactionAmount(amount).lienAllowed(lienAllowed)
|
||||
.reasonForBlock("unUsualActivity").build().getJson();
|
||||
}
|
||||
|
||||
private String getSavingsTransactionPaymentTypeJSON(final String amount, final String transactionDate, final String paymentTypeId) {
|
||||
final HashMap<String, String> map = new HashMap<>();
|
||||
map.put("locale", CommonConstants.LOCALE);
|
||||
map.put("dateFormat", CommonConstants.DATE_FORMAT);
|
||||
map.put("transactionDate", transactionDate);
|
||||
map.put("transactionAmount", amount);
|
||||
map.put("paymentTypeId", paymentTypeId);
|
||||
String savingsAccountWithdrawalJson = new Gson().toJson(map);
|
||||
LOG.info(savingsAccountWithdrawalJson);
|
||||
return savingsAccountWithdrawalJson;
|
||||
private String getSavingsTransactionPaymentTypeJSON(final String amount, final String transactionDate, final Long paymentTypeId) {
|
||||
return SavingsTransactionData.builder().transactionDate(transactionDate).transactionAmount(amount).paymentTypeId(paymentTypeId)
|
||||
.build().getJson();
|
||||
}
|
||||
|
||||
private String getCalculatedInterestForSavingsApplicationAsJSON() {
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* 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.savings;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import java.util.HashMap;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import org.apache.fineract.integrationtests.common.CommonConstants;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
public class SavingsTransactionData {
|
||||
|
||||
private String locale;
|
||||
private String dateFormat;
|
||||
private String transactionDate;
|
||||
private String transactionAmount;
|
||||
private Long paymentTypeId;
|
||||
private String withdrawnOnDate;
|
||||
private String note;
|
||||
private Boolean isBulk;
|
||||
private Boolean lienAllowed;
|
||||
private String reasonForBlock;
|
||||
|
||||
public String getJson() {
|
||||
final HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("locale", locale == null ? CommonConstants.LOCALE : locale);
|
||||
map.put("dateFormat", dateFormat == null ? CommonConstants.DATE_FORMAT : dateFormat);
|
||||
map.put("transactionDate", transactionDate);
|
||||
map.put("transactionAmount", transactionAmount);
|
||||
map.put("paymentTypeId", paymentTypeId);
|
||||
map.put("withdrawnOnDate", withdrawnOnDate);
|
||||
map.put("note", note);
|
||||
map.put("isBulk", isBulk);
|
||||
map.put("lienAllowed", lienAllowed);
|
||||
map.put("reasonForBlock", reasonForBlock);
|
||||
return new Gson().toJson(map);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user