From 470ff9a745801688e22311836e6142076b9ee2ad Mon Sep 17 00:00:00 2001 From: Jose Alberto Hernandez Date: Sat, 18 Jun 2022 00:43:00 -0500 Subject: [PATCH] Specify query parameters for LoanTransactionsApi retrieveTransaction --- .../batch/command/CommandStrategyUtils.java | 64 +++++++++++++++++++ .../GetTransactionByIdCommandStrategy.java | 38 +++++++++-- .../api/LoanTransactionsApiResource.java | 2 + .../loanaccount/api/SelfLoansApiResource.java | 5 +- ...GetTransactionByIdCommandStrategyTest.java | 36 +++++++---- 5 files changed, 126 insertions(+), 19 deletions(-) create mode 100644 fineract-provider/src/main/java/org/apache/fineract/batch/command/CommandStrategyUtils.java diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/CommandStrategyUtils.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/CommandStrategyUtils.java new file mode 100644 index 000000000..3510392d1 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/CommandStrategyUtils.java @@ -0,0 +1,64 @@ +/** + * 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.batch.command; + +import java.util.HashMap; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.apache.fineract.infrastructure.core.api.MutableUriInfo; + +public final class CommandStrategyUtils { + + private CommandStrategyUtils() { + + } + + /** + * Get query parameters from relative URL. + * + * @param relativeUrl + * the relative URL + * @return the query parameters in a map + */ + public static Map getQueryParameters(final String relativeUrl) { + final String queryParameterStr = StringUtils.substringAfter(relativeUrl, "?"); + final String[] queryParametersArray = StringUtils.split(queryParameterStr, "&"); + final Map queryParametersMap = new HashMap<>(); + for (String parameterStr : queryParametersArray) { + String[] keyValue = StringUtils.split(parameterStr, "="); + queryParametersMap.put(keyValue[0], keyValue[1]); + } + return queryParametersMap; + } + + /** + * Add query parameters(received in the relative URL) to URI info query parameters. + * + * @param uriInfo + * the URI info + * @param queryParameters + * the query parameters + */ + public static void addQueryParametersToUriInfo(final MutableUriInfo uriInfo, final Map queryParameters) { + for (Map.Entry entry : queryParameters.entrySet()) { + uriInfo.addAdditionalQueryParameter(entry.getKey(), entry.getValue()); + } + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetTransactionByIdCommandStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetTransactionByIdCommandStrategy.java index e736c6a54..dad95e275 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetTransactionByIdCommandStrategy.java +++ b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetTransactionByIdCommandStrategy.java @@ -19,14 +19,19 @@ package org.apache.fineract.batch.command.internal; import com.google.common.base.Splitter; +import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.ws.rs.core.UriInfo; +import liquibase.repackaged.org.apache.commons.lang3.StringUtils; import lombok.RequiredArgsConstructor; import org.apache.fineract.batch.command.CommandStrategy; +import org.apache.fineract.batch.command.CommandStrategyUtils; import org.apache.fineract.batch.domain.BatchRequest; import org.apache.fineract.batch.domain.BatchResponse; import org.apache.fineract.batch.exception.ErrorHandler; import org.apache.fineract.batch.exception.ErrorInfo; +import org.apache.fineract.infrastructure.core.api.MutableUriInfo; import org.apache.fineract.portfolio.loanaccount.api.LoanTransactionsApiResource; import org.apache.http.HttpStatus; import org.springframework.stereotype.Component; @@ -48,6 +53,7 @@ public class GetTransactionByIdCommandStrategy implements CommandStrategy { @Override public BatchResponse execute(final BatchRequest request, UriInfo uriInfo) { + final MutableUriInfo parameterizedUriInfo = new MutableUriInfo(uriInfo); final BatchResponse response = new BatchResponse(); final String responseBody; @@ -55,16 +61,37 @@ public class GetTransactionByIdCommandStrategy implements CommandStrategy { response.setRequestId(request.getRequestId()); response.setHeaders(request.getHeaders()); + final String relativeUrl = request.getRelativeUrl(); + // Get the loan and transaction ids for use in loanTransactionsApiResource - final List pathParameters = Splitter.on('/').splitToList(request.getRelativeUrl()); - final Long loanId = Long.parseLong(pathParameters.get(1)); - final Long transactionId = Long.parseLong(pathParameters.get(3)); + final List pathParameters = Splitter.on('/').splitToList(relativeUrl); + Long loanId = Long.parseLong(pathParameters.get(1)); + Long transactionId; + if (relativeUrl.indexOf('?') > 0) { + transactionId = Long.parseLong(StringUtils.substringBeforeLast(pathParameters.get(3), "?")); + } else { + transactionId = Long.parseLong(pathParameters.get(3)); + } + + Map queryParameters = new HashMap<>(); + if (relativeUrl.indexOf('?') > 0) { + queryParameters = CommandStrategyUtils.getQueryParameters(relativeUrl); + + // Add the query parameters sent in the relative URL to UriInfo + CommandStrategyUtils.addQueryParametersToUriInfo(parameterizedUriInfo, queryParameters); + } + + String fields = null; + if (!queryParameters.isEmpty()) { + if (queryParameters.containsKey("fields")) { + fields = queryParameters.get("fields"); + } + } // Try-catch blocks to map exceptions to appropriate status codes try { - // Calls 'retrieveTransaction' function from 'loanTransactionsApiResource' - responseBody = loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, uriInfo); + responseBody = loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, fields, uriInfo); response.setStatusCode(HttpStatus.SC_OK); @@ -83,5 +110,4 @@ public class GetTransactionByIdCommandStrategy implements CommandStrategy { return response; } - } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java index 985566905..f23cd5fce 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java @@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.loanaccount.api; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.parameters.RequestBody; @@ -206,6 +207,7 @@ public class LoanTransactionsApiResource { @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = LoanTransactionsApiResourceSwagger.GetLoansLoanIdTransactionsTransactionIdResponse.class))) }) public String retrieveTransaction(@PathParam("loanId") @Parameter(description = "loanId") final Long loanId, @PathParam("transactionId") @Parameter(description = "transactionId") final Long transactionId, + @QueryParam("fields") @Parameter(in = ParameterIn.QUERY, name = "fields", description = "Optional Loan Transaction attribute list to be in the response", required = false, example = "id,date,amount") final String fields, @Context final UriInfo uriInfo) { this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResource.java index 6fc70e4b7..2e9c104a4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResource.java @@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.self.loanaccount.api; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; @@ -62,7 +63,6 @@ import org.springframework.stereotype.Component; @Path("/self/loans") @Component @Scope("singleton") - @Tag(name = "Self Loans", description = "") public class SelfLoansApiResource { @@ -123,13 +123,14 @@ public class SelfLoansApiResource { @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = SelfLoansApiResourceSwagger.GetSelfLoansLoanIdTransactionsTransactionIdResponse.class))) }) public String retrieveTransaction(@PathParam("loanId") @Parameter(description = "loanId") final Long loanId, @PathParam("transactionId") @Parameter(description = "transactionId") final Long transactionId, + @QueryParam("fields") @Parameter(in = ParameterIn.QUERY, name = "fields", description = "Optional Loan Transaction attribute list to be in the response", required = false, example = "id,date,amount") final String fields, @Context final UriInfo uriInfo) { this.dataValidator.validateRetrieveTransaction(uriInfo); validateAppuserLoanMapping(loanId); - return this.loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, uriInfo); + return this.loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, fields, uriInfo); } @GET diff --git a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetTransactionByIdCommandStrategyTest.java b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetTransactionByIdCommandStrategyTest.java index bec2cfdc0..fe92be9dc 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetTransactionByIdCommandStrategyTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetTransactionByIdCommandStrategyTest.java @@ -20,9 +20,12 @@ package org.apache.fineract.batch.command.internal; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.when; +import java.util.stream.Stream; import javax.ws.rs.HttpMethod; import javax.ws.rs.core.UriInfo; import org.apache.commons.lang3.RandomStringUtils; @@ -33,22 +36,30 @@ import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionNotFoundException; import org.apache.http.HttpStatus; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mock; import org.mockito.MockitoAnnotations; public class GetTransactionByIdCommandStrategyTest { + private static Stream provideQueryParameters() { + return Stream.of(Arguments.of(null, 0), Arguments.of("id,date,amount", 1)); + } + /** * Test {@link GetTransactionByIdCommandStrategy#execute} happy path scenario. */ - @Test - public void testExecuteSuccessScenario() { + @ParameterizedTest + @MethodSource("provideQueryParameters") + public void testExecuteSuccessScenario(final String fields, final int noOfQueryParams) { // given final TestContext testContext = new TestContext(); final Long loanId = Long.valueOf(RandomStringUtils.randomNumeric(4)); final Long transactionId = Long.valueOf(RandomStringUtils.randomNumeric(4)); - final BatchRequest request = getBatchRequest(loanId, transactionId); + final BatchRequest request = getBatchRequest(loanId, transactionId, fields); final String responseBody = "{\"id\":12,\"officeId\":1,\"officeName\":\"Head Office\",\"type\":{\"id\":10,\"code\":" + "\"loanTransactionType.accrual\",\"value\":\"Accrual\",\"disbursement\":false,\"repaymentAtDisbursement\":false," + "\"repayment\":false,\"contra\":false,\"waiveInterest\":false,\"waiveCharges\":false,\"accrual\":true,\"writeOff\":false," @@ -60,7 +71,7 @@ public class GetTransactionByIdCommandStrategyTest { + "\"unrecognizedIncomePortion\":0,\"outstandingLoanBalance\":0,\"submittedOnDate\":[2022,3,29],\"manuallyReversed\":false," + "\"loanChargePaidByList\":[],\"numberOfRepayments\":0}"; - given(testContext.loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, testContext.uriInfo)) + given(testContext.loanTransactionsApiResource.retrieveTransaction(eq(loanId), eq(transactionId), eq(fields), any(UriInfo.class))) .willReturn(responseBody); // when @@ -82,9 +93,9 @@ public class GetTransactionByIdCommandStrategyTest { final TestContext testContext = new TestContext(); final Long loanId = Long.valueOf(RandomStringUtils.randomNumeric(4)); final Long transactionId = Long.valueOf(RandomStringUtils.randomNumeric(4)); - final BatchRequest request = getBatchRequest(loanId, transactionId); + final BatchRequest request = getBatchRequest(loanId, transactionId, null); - given(testContext.loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, testContext.uriInfo)) + given(testContext.loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, null, testContext.uriInfo)) .willThrow(new RuntimeException("Some error")); // when @@ -106,9 +117,9 @@ public class GetTransactionByIdCommandStrategyTest { final TestContext testContext = new TestContext(); final Long loanId = Long.valueOf(RandomStringUtils.randomNumeric(4)); final Long transactionId = Long.valueOf(RandomStringUtils.randomNumeric(4)); - final BatchRequest request = getBatchRequest(loanId, transactionId); + final BatchRequest request = getBatchRequest(loanId, transactionId, null); - given(testContext.loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, testContext.uriInfo)) + given(testContext.loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, null, testContext.uriInfo)) .willThrow(new LoanNotFoundException(loanId)); // when @@ -129,9 +140,9 @@ public class GetTransactionByIdCommandStrategyTest { final TestContext testContext = new TestContext(); final Long loanId = Long.valueOf(RandomStringUtils.randomNumeric(4)); final Long transactionId = Long.valueOf(RandomStringUtils.randomNumeric(4)); - final BatchRequest request = getBatchRequest(loanId, transactionId); + final BatchRequest request = getBatchRequest(loanId, transactionId, null); - when(testContext.loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, testContext.uriInfo)) + when(testContext.loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, null, testContext.uriInfo)) .thenThrow(new LoanTransactionNotFoundException(transactionId)); final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo); @@ -151,10 +162,13 @@ public class GetTransactionByIdCommandStrategyTest { * the transaction id * @return BatchRequest */ - private BatchRequest getBatchRequest(final Long loanId, final Long transactionId) { + private BatchRequest getBatchRequest(final Long loanId, final Long transactionId, final String fields) { final BatchRequest br = new BatchRequest(); String relativeUrl = "loans/" + loanId + "/transactions/" + transactionId; + if (fields != null) { + relativeUrl = relativeUrl + "?fields=" + fields; + } br.setRequestId(Long.valueOf(RandomStringUtils.randomNumeric(5))); br.setRelativeUrl(relativeUrl);