Fine tuning the batch APIs and minor adjustments
This commit is contained in:
committed by
Arnold Gálovics
parent
a89fe53937
commit
77fd4ff4c1
@@ -77,6 +77,7 @@ import org.apache.fineract.client.services.JournalEntriesApi;
|
||||
import org.apache.fineract.client.services.ListReportMailingJobHistoryApi;
|
||||
import org.apache.fineract.client.services.LoanChargesApi;
|
||||
import org.apache.fineract.client.services.LoanCollateralApi;
|
||||
import org.apache.fineract.client.services.LoanDisbursementDetailsApi;
|
||||
import org.apache.fineract.client.services.LoanProductsApi;
|
||||
import org.apache.fineract.client.services.LoanReschedulingApi;
|
||||
import org.apache.fineract.client.services.LoanTransactionsApi;
|
||||
@@ -208,6 +209,7 @@ public final class FineractClient {
|
||||
public final LoanProductsApi loanProducts;
|
||||
public final LoanReschedulingApi loanSchedules;
|
||||
public final LoansApi loans;
|
||||
public final LoanDisbursementDetailsApi loanDisbursementDetails;
|
||||
public final LoanTransactionsApi loanTransactions;
|
||||
public final MakerCheckerOr4EyeFunctionalityApi makerCheckers;
|
||||
public final MappingFinancialActivitiesToAccountsApi financialActivyAccountMappings;
|
||||
@@ -318,6 +320,7 @@ public final class FineractClient {
|
||||
loanProducts = retrofit.create(LoanProductsApi.class);
|
||||
loanSchedules = retrofit.create(LoanReschedulingApi.class);
|
||||
loans = retrofit.create(LoansApi.class);
|
||||
loanDisbursementDetails = retrofit.create(LoanDisbursementDetailsApi.class);
|
||||
loanTransactions = retrofit.create(LoanTransactionsApi.class);
|
||||
makerCheckers = retrofit.create(MakerCheckerOr4EyeFunctionalityApi.class);
|
||||
financialActivyAccountMappings = retrofit.create(MappingFinancialActivitiesToAccountsApi.class);
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.apache.fineract.batch.api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||
@@ -92,9 +93,9 @@ public class BatchApiResource {
|
||||
@Operation(summary = "Batch requests in a single transaction", description = "The Apache Fineract Batch API is also capable of executing all the requests in a single transaction, by setting a Query Parameter, \"enclosingTransaction=true\". So, if one or more of the requests in a batch returns an erroneous response all of the Data base transactions made by other successful requests will be rolled back.\n"
|
||||
+ "\n"
|
||||
+ "If there has been a rollback in a transaction then a single response will be provided, with a '400' status code and a body consisting of the error details of the first failed request.")
|
||||
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = BatchApiResourceSwagger.PostBatchesRequest.class, description = "request body")))
|
||||
@RequestBody(required = true, content = @Content(array = @ArraySchema(schema = @Schema(implementation = BatchRequest.class, description = "request body"))))
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "Success", content = @Content(schema = @Schema(implementation = BatchResponse.class))) })
|
||||
@ApiResponse(responseCode = "200", description = "Success", content = @Content(array = @ArraySchema(schema = @Schema(implementation = BatchResponse.class)))) })
|
||||
public String handleBatchRequests(
|
||||
@DefaultValue("false") @QueryParam("enclosingTransaction") @Parameter(description = "enclosingTransaction", required = false) final boolean enclosingTransaction,
|
||||
@Parameter(hidden = true) final String jsonRequestString, @Context UriInfo uriInfo) {
|
||||
|
||||
+5
@@ -84,6 +84,9 @@ public class CommandStrategyProvider {
|
||||
this.commandStrategies.put(CommandContext.resource("clients").method("POST").build(), "createClientCommandStrategy");
|
||||
this.commandStrategies.put(CommandContext.resource("clients\\/\\d+").method("PUT").build(), "updateClientCommandStrategy");
|
||||
this.commandStrategies.put(CommandContext.resource("loans").method("POST").build(), "applyLoanCommandStrategy");
|
||||
this.commandStrategies.put(CommandContext.resource("loans\\/\\d+").method("GET").build(), "getLoanByIdCommandStrategy");
|
||||
this.commandStrategies.put(CommandContext.resource("loans/\\d+(\\?(\\w+(?:\\=[\\w,]+|&)+)+)").method("GET").build(),
|
||||
"getLoanByIdCommandStrategy");
|
||||
this.commandStrategies.put(CommandContext.resource("savingsaccounts").method("POST").build(), "applySavingsCommandStrategy");
|
||||
this.commandStrategies.put(CommandContext.resource("loans\\/\\d+\\/charges").method("POST").build(), "createChargeCommandStrategy");
|
||||
this.commandStrategies.put(CommandContext.resource("loans\\/\\d+\\/charges").method("GET").build(),
|
||||
@@ -98,6 +101,8 @@ public class CommandStrategyProvider {
|
||||
"disburseLoanCommandStrategy");
|
||||
this.commandStrategies.put(CommandContext.resource("rescheduleloans\\/\\d+\\?command=approve").method("POST").build(),
|
||||
"approveLoanRescheduleCommandStrategy");
|
||||
this.commandStrategies.put(CommandContext.resource("loans\\/\\d+\\/transactions\\/\\d+").method("GET").build(),
|
||||
"getTransactionByIdCommandStrategy");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* 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.internal;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.batch.command.CommandStrategy;
|
||||
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.LoansApiResource;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Implements {@link CommandStrategy} and get loan by id. It passes the contents of the body from the BatchRequest to
|
||||
* {@link LoansApiResource} and gets back the response. This class will also catch any errors raised by
|
||||
* {@link LoansApiResource} and map those errors to appropriate status codes in BatchResponse.
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class GetLoanByIdCommandStrategy implements CommandStrategy {
|
||||
|
||||
/**
|
||||
* Loans api resource {@link LoansApiResource}.
|
||||
*/
|
||||
private final LoansApiResource loansApiResource;
|
||||
|
||||
@Override
|
||||
public BatchResponse execute(final BatchRequest request, final UriInfo uriInfo) {
|
||||
final MutableUriInfo parameterizedUriInfo = new MutableUriInfo(uriInfo);
|
||||
|
||||
final BatchResponse response = new BatchResponse();
|
||||
final String responseBody;
|
||||
|
||||
response.setRequestId(request.getRequestId());
|
||||
response.setHeaders(request.getHeaders());
|
||||
|
||||
final String relativeUrl = request.getRelativeUrl();
|
||||
Long loanId;
|
||||
|
||||
// Try-catch blocks to map exceptions to appropriate status codes
|
||||
try {
|
||||
// uriInfo will contain the query parameter value(s) that are sent in the actual batch uri.
|
||||
// for example: batches?enclosingTransaction=true
|
||||
// But the query parameters that are sent in the batch relative url has to be sent to
|
||||
// LoansApiResource.retrieveLoan
|
||||
// To use the relative url query parameters
|
||||
// - Parse and fetch the query parameters sent in the relative url
|
||||
// (loans/66?fields=id,principal,annualInterestRate)
|
||||
// - Add them to the UriInfo query parameters list
|
||||
// - Call loansApiResource.retrieveLoan(loanId, false, uriInfo)
|
||||
// - Remove the relative url query parameters from UriInfo in the finally (after loan details are retrieved)
|
||||
if (relativeUrl.indexOf('?') > 0) {
|
||||
loanId = Long.parseLong(StringUtils.substringBetween(relativeUrl, "/", "?"));
|
||||
Map<String, String> queryParameters = getQueryParameters(relativeUrl);
|
||||
|
||||
// Add the query parameters sent in the relative URL to UriInfo
|
||||
addQueryParametersToUriInfo(parameterizedUriInfo, queryParameters);
|
||||
} else {
|
||||
loanId = Long.parseLong(StringUtils.substringAfter(relativeUrl, "/"));
|
||||
}
|
||||
|
||||
// Calls 'retrieveLoan' function from 'LoansApiResource' to
|
||||
// get the loan details based on the loan id
|
||||
responseBody = loansApiResource.retrieveLoan(loanId, false, parameterizedUriInfo);
|
||||
|
||||
response.setStatusCode(HttpStatus.SC_OK);
|
||||
|
||||
// Sets the response after retrieving the loan
|
||||
response.setBody(responseBody);
|
||||
|
||||
} catch (RuntimeException e) {
|
||||
|
||||
// Gets an object of type ErrorInfo, containing information about
|
||||
// raised exception
|
||||
ErrorInfo ex = ErrorHandler.handler(e);
|
||||
|
||||
response.setStatusCode(ex.getStatusCode());
|
||||
response.setBody(ex.getMessage());
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get query parameters from relative URL.
|
||||
*
|
||||
* @param relativeUrl
|
||||
* the relative URL
|
||||
* @return the query parameters in a map
|
||||
*/
|
||||
private Map<String, String> getQueryParameters(final String relativeUrl) {
|
||||
final String queryParameterStr = StringUtils.substringAfter(relativeUrl, "?");
|
||||
final String[] queryParametersArray = StringUtils.split(queryParameterStr, "&");
|
||||
final Map<String, String> 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
|
||||
*/
|
||||
private void addQueryParametersToUriInfo(final MutableUriInfo uriInfo, final Map<String, String> queryParameters) {
|
||||
for (Map.Entry<String, String> entry : queryParameters.entrySet()) {
|
||||
uriInfo.addAdditionalQueryParameter(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* 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.internal;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import java.util.List;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.batch.command.CommandStrategy;
|
||||
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.portfolio.loanaccount.api.LoanTransactionsApiResource;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Implements {@link CommandStrategy} to retrieve a transaction by id. It passes the contents of the body from the
|
||||
* BatchRequest to {@link LoanTransactionsApiResource} and gets back the response. This class will also catch any errors
|
||||
* raised by {@link LoanTransactionsApiResource} and map those errors to appropriate status codes in BatchResponse.
|
||||
*
|
||||
* @see CommandStrategy
|
||||
* @see BatchRequest
|
||||
* @see BatchResponse
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class GetTransactionByIdCommandStrategy implements CommandStrategy {
|
||||
|
||||
private final LoanTransactionsApiResource loanTransactionsApiResource;
|
||||
|
||||
@Override
|
||||
public BatchResponse execute(final BatchRequest request, UriInfo uriInfo) {
|
||||
|
||||
final BatchResponse response = new BatchResponse();
|
||||
final String responseBody;
|
||||
|
||||
response.setRequestId(request.getRequestId());
|
||||
response.setHeaders(request.getHeaders());
|
||||
|
||||
// Get the loan and transaction ids for use in loanTransactionsApiResource
|
||||
final List<String> pathParameters = Splitter.on('/').splitToList(request.getRelativeUrl());
|
||||
final Long loanId = Long.parseLong(pathParameters.get(1));
|
||||
final Long transactionId = Long.parseLong(pathParameters.get(3));
|
||||
|
||||
// Try-catch blocks to map exceptions to appropriate status codes
|
||||
try {
|
||||
|
||||
// Calls 'retrieveTransaction' function from 'loanTransactionsApiResource'
|
||||
responseBody = loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, uriInfo);
|
||||
|
||||
response.setStatusCode(HttpStatus.SC_OK);
|
||||
|
||||
// Sets the body of the response after retrieving the transaction
|
||||
response.setBody(responseBody);
|
||||
|
||||
} catch (RuntimeException e) {
|
||||
|
||||
// Gets an object of type ErrorInfo, containing information about
|
||||
// raised exception
|
||||
ErrorInfo ex = ErrorHandler.handler(e);
|
||||
|
||||
response.setStatusCode(ex.getStatusCode());
|
||||
response.setBody(ex.getMessage());
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -46,7 +46,7 @@ public abstract class AbstractWorkbookPopulator implements WorkbookPopulator {
|
||||
}
|
||||
|
||||
protected void writeLong(int colIndex, Row row, long value) {
|
||||
row.createCell(colIndex).setCellValue(value);
|
||||
row.createCell(colIndex).setCellValue((double) value);
|
||||
}
|
||||
|
||||
protected void writeString(int colIndex, Row row, String value) {
|
||||
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* 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.infrastructure.core.api;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import javax.ws.rs.core.MultivaluedHashMap;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.PathSegment;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class MutableUriInfo implements UriInfo {
|
||||
|
||||
private final UriInfo delegate;
|
||||
|
||||
@Getter
|
||||
private final MultivaluedMap<String, String> additionalQueryParameters = new MultivaluedHashMap<>();
|
||||
|
||||
@Override
|
||||
public MultivaluedMap<String, String> getQueryParameters() {
|
||||
return fillAdditionalQueryParameters(delegate.getQueryParameters());
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultivaluedMap<String, String> getQueryParameters(boolean decode) {
|
||||
return fillAdditionalQueryParameters(delegate.getQueryParameters(decode));
|
||||
}
|
||||
|
||||
private MultivaluedMap<String, String> fillAdditionalQueryParameters(MultivaluedMap<String, String> queryParameters) {
|
||||
MultivaluedMap<String, String> newQueryParameters = new MultivaluedHashMap<>(queryParameters);
|
||||
newQueryParameters.putAll(additionalQueryParameters);
|
||||
return newQueryParameters;
|
||||
}
|
||||
|
||||
public void addAdditionalQueryParameter(String key, String value) {
|
||||
additionalQueryParameters.add(key, value);
|
||||
}
|
||||
|
||||
public void putAdditionalQueryParameter(String key, List<String> values) {
|
||||
additionalQueryParameters.put(key, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return delegate.getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath(boolean decode) {
|
||||
return delegate.getPath(decode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PathSegment> getPathSegments() {
|
||||
return delegate.getPathSegments();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PathSegment> getPathSegments(boolean decode) {
|
||||
return delegate.getPathSegments(decode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getRequestUri() {
|
||||
return delegate.getRequestUri();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UriBuilder getRequestUriBuilder() {
|
||||
return delegate.getRequestUriBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getAbsolutePath() {
|
||||
return delegate.getAbsolutePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UriBuilder getAbsolutePathBuilder() {
|
||||
return delegate.getAbsolutePathBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getBaseUri() {
|
||||
return delegate.getBaseUri();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UriBuilder getBaseUriBuilder() {
|
||||
return delegate.getBaseUriBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultivaluedMap<String, String> getPathParameters() {
|
||||
return delegate.getPathParameters();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultivaluedMap<String, String> getPathParameters(boolean decode) {
|
||||
return delegate.getPathParameters(decode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMatchedURIs() {
|
||||
return delegate.getMatchedURIs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMatchedURIs(boolean decode) {
|
||||
return delegate.getMatchedURIs(decode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> getMatchedResources() {
|
||||
return delegate.getMatchedResources();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI resolve(URI uri) {
|
||||
return delegate.resolve(uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI relativize(URI uri) {
|
||||
return delegate.relativize(uri);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -306,7 +306,7 @@ public class DatatablesApiResource {
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(summary = "Update Entry in Data Table (One to One)", description = "Updates the row (if it exists) of the data table.")
|
||||
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = DatatablesApiResourceSwagger.PutDataTablesAppTableIdRequest.class)))
|
||||
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = String.class)))
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DatatablesApiResourceSwagger.PutDataTablesAppTableIdResponse.class))) })
|
||||
public String updateDatatableEntryOnetoOne(@PathParam("datatable") @Parameter(description = "datatable") final String datatable,
|
||||
@@ -328,7 +328,7 @@ public class DatatablesApiResource {
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(summary = "Update Entry in Data Table (One to Many)", description = "Updates the row (if it exists) of the data table.")
|
||||
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = DatatablesApiResourceSwagger.PutDataTablesAppTableIdDatatableIdRequest.class)))
|
||||
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = String.class)))
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DatatablesApiResourceSwagger.PutDataTablesAppTableIdDatatableIdResponse.class))) })
|
||||
public String updateDatatableEntryOneToMany(@PathParam("datatable") @Parameter(description = "datatable") final String datatable,
|
||||
|
||||
+15
-43
@@ -20,6 +20,7 @@ package org.apache.fineract.infrastructure.dataqueries.api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
|
||||
import org.apache.fineract.infrastructure.dataqueries.data.ResultsetRowData;
|
||||
|
||||
@@ -218,17 +219,6 @@ final class DatatablesApiResourceSwagger {
|
||||
public List<ResultsetRowData> data;
|
||||
}
|
||||
|
||||
@Schema(description = "PutDataTablesAppTableIdRequest")
|
||||
public static final class PutDataTablesAppTableIdRequest {
|
||||
|
||||
private PutDataTablesAppTableIdRequest() {
|
||||
|
||||
}
|
||||
|
||||
@Schema(example = "Livestock sales updated")
|
||||
public String BusinessDescription;
|
||||
}
|
||||
|
||||
@Schema(description = "PutDataTablesAppTableIdResponse")
|
||||
public static final class PutDataTablesAppTableIdResponse {
|
||||
|
||||
@@ -236,40 +226,15 @@ final class DatatablesApiResourceSwagger {
|
||||
|
||||
}
|
||||
|
||||
static final class PutDataTablesAppTableIdResponseChanges {
|
||||
|
||||
private PutDataTablesAppTableIdResponseChanges() {}
|
||||
|
||||
@Schema(example = "Livestock sales updated")
|
||||
public String BusinessDescription;
|
||||
}
|
||||
|
||||
@Schema(example = "1")
|
||||
public Long officeId;
|
||||
@Schema(example = "1")
|
||||
public Long clientId;
|
||||
@Schema(example = "1")
|
||||
public Long loanId;
|
||||
@Schema(example = "1")
|
||||
public Long resourceId;
|
||||
public PutDataTablesAppTableIdResponseChanges changes;
|
||||
}
|
||||
|
||||
@Schema(description = "PutDataTablesAppTableIdDatatableIdRequest")
|
||||
public static final class PutDataTablesAppTableIdDatatableIdRequest {
|
||||
|
||||
private PutDataTablesAppTableIdDatatableIdRequest() {
|
||||
|
||||
}
|
||||
|
||||
@Schema(example = "01 June 1982")
|
||||
public String DateOfBirth;
|
||||
@Schema(example = "5")
|
||||
public Long Education_cdHighest;
|
||||
@Schema(example = "June")
|
||||
public String Name;
|
||||
@Schema(example = "More notes")
|
||||
public String OtherNotes;
|
||||
@Schema(example = "20")
|
||||
public Long PointsScore;
|
||||
@Schema(example = "dd MMMM yyyy")
|
||||
public String dateFormat;
|
||||
@Schema(example = "en")
|
||||
public String locale;
|
||||
public Map<String, Object> changes;
|
||||
}
|
||||
|
||||
@Schema(description = "PutDataTablesAppTableIdDatatableIdResponse ")
|
||||
@@ -279,8 +244,15 @@ final class DatatablesApiResourceSwagger {
|
||||
|
||||
}
|
||||
|
||||
@Schema(example = "1")
|
||||
public Long officeId;
|
||||
@Schema(example = "1")
|
||||
public Long clientId;
|
||||
@Schema(example = "1")
|
||||
public Long loanId;
|
||||
@Schema(example = "1")
|
||||
public Long resourceId;
|
||||
public Map<String, Object> changes;
|
||||
}
|
||||
|
||||
@Schema(description = "DeleteDataTablesDatatableAppTableIdResponse ")
|
||||
|
||||
+2
-2
@@ -51,7 +51,7 @@ final class CurrenciesApiResourceSwagger {
|
||||
|
||||
@Schema(example = "[\"KES\",\n" + " \"BND\",\n" + " \"LBP\",\n" + " \"GHC\",\n" + " \"USD\",\n"
|
||||
+ " \"XOF\",\n" + " \"AED\",\n" + " \"AMD\"]")
|
||||
public String currencies;
|
||||
public String[] currencies;
|
||||
|
||||
}
|
||||
|
||||
@@ -64,6 +64,6 @@ final class CurrenciesApiResourceSwagger {
|
||||
|
||||
@Schema(example = "[\"KES\",\n" + " \"BND\",\n" + " \"LBP\",\n" + " \"GHC\",\n" + " \"USD\",\n"
|
||||
+ " \"XOF\",\n" + " \"AED\",\n" + " \"AMD\"]")
|
||||
public String currencies;
|
||||
public String[] currencies;
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -135,6 +135,10 @@ final class ChargesApiResourceSwagger {
|
||||
public Integer chargePaymentMode;
|
||||
@Schema(example = "true")
|
||||
public String active;
|
||||
@Schema(example = "dd MMMM")
|
||||
public String monthDayFormat;
|
||||
@Schema(example = "false")
|
||||
public String penalty;
|
||||
}
|
||||
|
||||
@Schema(description = "PostChargesResponse")
|
||||
|
||||
+4
@@ -302,6 +302,8 @@ final class ClientsApiResourceSwagger {
|
||||
public String externalId;
|
||||
@Schema(example = "Client_LastName")
|
||||
public String lastname;
|
||||
@Schema(example = "[2013, 1, 1]")
|
||||
public LocalDate dateOfBirth;
|
||||
@Schema(example = "1")
|
||||
public Integer groupId;
|
||||
@Schema(example = "dd MMMM yyyy")
|
||||
@@ -312,6 +314,8 @@ final class ClientsApiResourceSwagger {
|
||||
public Boolean active;
|
||||
@Schema(example = "04 March 2009")
|
||||
public String activationDate;
|
||||
@Schema(example = "+353851239876")
|
||||
public String mobileNo;
|
||||
@Schema(description = "List of PostClientsDatatable")
|
||||
public List<PostClientsDatatable> datatables;
|
||||
@Schema(description = "Address requests")
|
||||
|
||||
+19
-2
@@ -133,6 +133,8 @@ final class LoanTransactionsApiResourceSwagger {
|
||||
public GetLoansType type;
|
||||
@Schema(example = "[2012, 5, 14]")
|
||||
public LocalDate date;
|
||||
@Schema(example = "[2012, 5, 14]")
|
||||
public LocalDate submittedOnDate;
|
||||
@Schema(example = "false")
|
||||
public Boolean manuallyReversed;
|
||||
public GetLoansCurrency currency;
|
||||
@@ -146,6 +148,21 @@ final class LoanTransactionsApiResourceSwagger {
|
||||
public static final class PostLoansLoanIdTransactionsRequest {
|
||||
|
||||
private PostLoansLoanIdTransactionsRequest() {}
|
||||
|
||||
@Schema(example = "en_GB")
|
||||
public String locale;
|
||||
@Schema(example = "dd MMMM yyyy")
|
||||
public String dateFormat;
|
||||
@Schema(example = "[2012, 5, 25]")
|
||||
public LocalDate transactionDate;
|
||||
@Schema(example = "50000.00")
|
||||
public Double transactionAmount;
|
||||
@Schema(example = "An optional note about why your adjusting or changing the transaction.")
|
||||
public String note;
|
||||
@Schema(example = "3e7791ce-aa10-11ec-b909-0242ac120002")
|
||||
public String externalId;
|
||||
@Schema(example = "3")
|
||||
public Integer paymentTypeId;
|
||||
}
|
||||
|
||||
@Schema(description = "PostLoansLoanIdTransactionsResponse")
|
||||
@@ -170,8 +187,8 @@ final class LoanTransactionsApiResourceSwagger {
|
||||
public String locale;
|
||||
@Schema(example = "dd MMMM yyyy")
|
||||
public String dateFormat;
|
||||
@Schema(example = "25 May 2012")
|
||||
public String transactionDate;
|
||||
@Schema(example = "[2012, 5, 25]")
|
||||
public LocalDate transactionDate;
|
||||
@Schema(example = "50,000.00")
|
||||
public Double transactionAmount;
|
||||
@Schema(example = "An optional note about why your adjusting or changing the transaction.")
|
||||
|
||||
+228
-2
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.api;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -230,6 +231,124 @@ final class LoansApiResourceSwagger {
|
||||
public String disbursedByLastname;
|
||||
@Schema(example = "[2012, 4, 10]")
|
||||
public LocalDate expectedMaturityDate;
|
||||
@Schema(example = "[2012, 4, 3]")
|
||||
public LocalDate closedOnDate;
|
||||
}
|
||||
|
||||
static final class GetLoansLoanIdRepaymentSchedule {
|
||||
|
||||
private GetLoansLoanIdRepaymentSchedule() {}
|
||||
|
||||
public GetLoansLoanIdCurrency currency;
|
||||
@Schema(example = "30")
|
||||
public Long loanTermInDays;
|
||||
@Schema(example = "200.000000")
|
||||
public Double totalPrincipalDisbursed;
|
||||
@Schema(example = "200.00")
|
||||
public Double totalPrincipalExpected;
|
||||
@Schema(example = "200.00")
|
||||
public Double totalPrincipalPaid;
|
||||
@Schema(example = "0.00")
|
||||
public Double totalInterestCharged;
|
||||
@Schema(example = "0.00")
|
||||
public Double totalFeeChargesCharged;
|
||||
@Schema(example = "0.00")
|
||||
public Double totalPenaltyChargesCharged;
|
||||
@Schema(example = "0.00")
|
||||
public Double totalWaived;
|
||||
@Schema(example = "0.00")
|
||||
public Double totalWrittenOff;
|
||||
@Schema(example = "200.00")
|
||||
public Double totalRepaymentExpected;
|
||||
@Schema(example = "200.00")
|
||||
public Double totalPaidInAdvance;
|
||||
@Schema(example = "0.00")
|
||||
public Double totalPaidLate;
|
||||
@Schema(example = "0.00")
|
||||
public Double totalOutstanding;
|
||||
public Set<GetLoansLoanIdRepaymentPeriod> periods;
|
||||
}
|
||||
|
||||
static final class GetLoansLoanIdRepaymentPeriod {
|
||||
|
||||
private GetLoansLoanIdRepaymentPeriod() {}
|
||||
|
||||
@Schema(example = "1")
|
||||
public Integer period;
|
||||
@Schema(example = "[2012, 4, 3]")
|
||||
public LocalDate fromDate;
|
||||
@Schema(example = "[2012, 4, 3]")
|
||||
public LocalDate dueDate;
|
||||
@Schema(example = "[2012, 4, 3]")
|
||||
public LocalDate obligationsMetOnDate;
|
||||
@Schema(example = "true")
|
||||
public Boolean complete;
|
||||
@Schema(example = "30")
|
||||
public Long daysInPeriod;
|
||||
@Schema(example = "200.000000")
|
||||
public Double principalOriginalDue;
|
||||
@Schema(example = "200.000000")
|
||||
public Double principalDue;
|
||||
@Schema(example = "200.000000")
|
||||
public Double principalPaid;
|
||||
@Schema(example = "0")
|
||||
public Long principalWrittenOff;
|
||||
@Schema(example = "20.000000")
|
||||
public Double principalOutstanding;
|
||||
@Schema(example = "20.000000")
|
||||
public Double principalLoanBalanceOutstanding;
|
||||
@Schema(example = "0")
|
||||
public Long interestOriginalDue;
|
||||
@Schema(example = "0")
|
||||
public Long interestDue;
|
||||
@Schema(example = "0")
|
||||
public Long interestPaid;
|
||||
@Schema(example = "0")
|
||||
public Long interestWaived;
|
||||
@Schema(example = "0")
|
||||
public Long interestWrittenOff;
|
||||
@Schema(example = "0")
|
||||
public Long interestOutstanding;
|
||||
@Schema(example = "0")
|
||||
public Long feeChargesDue;
|
||||
@Schema(example = "20")
|
||||
public Long feeChargesPaid;
|
||||
@Schema(example = "20")
|
||||
public Long feeChargesWaived;
|
||||
@Schema(example = "20")
|
||||
public Long feeChargesWrittenOff;
|
||||
@Schema(example = "20")
|
||||
public Long feeChargesOutstanding;
|
||||
@Schema(example = "20")
|
||||
public Long penaltyChargesDue;
|
||||
@Schema(example = "20")
|
||||
public Long penaltyChargesPaid;
|
||||
@Schema(example = "20")
|
||||
public Long penaltyChargesWaived;
|
||||
@Schema(example = "20")
|
||||
public Long penaltyChargesWrittenOff;
|
||||
@Schema(example = "20")
|
||||
public Long penaltyChargesOutstanding;
|
||||
@Schema(example = "20.000000")
|
||||
public Double totalOriginalDueForPeriod;
|
||||
@Schema(example = "20.000000")
|
||||
public Double totalDueForPeriod;
|
||||
@Schema(example = "20.000000")
|
||||
public Double totalPaidForPeriod;
|
||||
@Schema(example = "20.000000")
|
||||
public Double totalPaidInAdvanceForPeriod;
|
||||
@Schema(example = "20")
|
||||
public Long totalPaidLateForPeriod;
|
||||
@Schema(example = "20")
|
||||
public Long totalWaivedForPeriod;
|
||||
@Schema(example = "20")
|
||||
public Long totalWrittenOffForPeriod;
|
||||
@Schema(example = "200.000000")
|
||||
public Double totalOutstandingForPeriod;
|
||||
@Schema(example = "20")
|
||||
public Long totalActualCostOfLoanForPeriod;
|
||||
@Schema(example = "200.000000")
|
||||
public Double totalInstallmentAmountForPeriod;
|
||||
}
|
||||
|
||||
static final class GetLoansLoanIdSummary {
|
||||
@@ -448,7 +567,11 @@ final class LoansApiResourceSwagger {
|
||||
public GetLoansLoanIdLoanType loanType;
|
||||
public GetLoansLoanIdCurrency currency;
|
||||
@Schema(example = "1000000")
|
||||
public Long principal;
|
||||
public BigDecimal principal;
|
||||
@Schema(example = "1000.000000")
|
||||
public Double approvedPrincipal;
|
||||
@Schema(example = "200.000000")
|
||||
public Double netDisbursalAmount;
|
||||
@Schema(example = "12")
|
||||
public Integer termFrequency;
|
||||
public GetLoansLoanIdTermPeriodFrequencyType termPeriodFrequencyType;
|
||||
@@ -471,6 +594,7 @@ final class LoansApiResourceSwagger {
|
||||
public Integer transactionProcessingStrategyId;
|
||||
public GetLoansLoanIdTimeline timeline;
|
||||
public GetLoansLoanIdSummary summary;
|
||||
public GetLoansLoanIdRepaymentSchedule repaymentSchedule;
|
||||
}
|
||||
|
||||
@Schema(description = "GetLoansResponse")
|
||||
@@ -486,8 +610,20 @@ final class LoansApiResourceSwagger {
|
||||
@Schema(description = "PostLoansRequest")
|
||||
public static final class PostLoansRequest {
|
||||
|
||||
static final class PostLoansDisbursementData {
|
||||
|
||||
private PostLoansDisbursementData() {}
|
||||
|
||||
@Schema(example = "[2013, 11, 1]")
|
||||
public LocalDate expectedDisbursementDate;
|
||||
@Schema(example = "1000.00")
|
||||
public Double principal;
|
||||
}
|
||||
|
||||
private PostLoansRequest() {}
|
||||
|
||||
@Schema(example = "1")
|
||||
public Long clientId;
|
||||
@Schema(example = "dd MMMM yyyy")
|
||||
public String dateFormat;
|
||||
@Schema(example = "en_GB")
|
||||
@@ -495,7 +631,7 @@ final class LoansApiResourceSwagger {
|
||||
@Schema(example = "1")
|
||||
public Integer productId;
|
||||
@Schema(example = "100,000.00")
|
||||
public Double principal;
|
||||
public String principal;
|
||||
@Schema(example = "12")
|
||||
public Integer loanTermFrequency;
|
||||
@Schema(example = "2")
|
||||
@@ -522,6 +658,14 @@ final class LoansApiResourceSwagger {
|
||||
public Integer transactionProcessingStrategyId;
|
||||
@Schema(example = "360", allowableValues = "1, 360, 364, 36")
|
||||
public Integer daysInYearType;
|
||||
@Schema(example = "individual")
|
||||
public String loanType;
|
||||
@Schema(example = "[2012, 4, 3]")
|
||||
public LocalDate submittedOnDate;
|
||||
@Schema(example = "786444UUUYYH7")
|
||||
public String externalId;
|
||||
@Schema(description = "List of PostLoansDisbursementData")
|
||||
public List<PostLoansDisbursementData> disbursementData;
|
||||
}
|
||||
|
||||
@Schema(description = "PostLoansResponse")
|
||||
@@ -583,6 +727,14 @@ final class LoansApiResourceSwagger {
|
||||
@Schema(example = "0")
|
||||
public Long totalOutstanding;
|
||||
public Set<PostLoansRepaymentSchedulePeriods> periods;
|
||||
@Schema(example = "2")
|
||||
public Integer officeId;
|
||||
@Schema(example = "1")
|
||||
public Integer clientId;
|
||||
@Schema(example = "1")
|
||||
public Integer loanId;
|
||||
@Schema(example = "1")
|
||||
public Integer resourceId;
|
||||
}
|
||||
|
||||
@Schema(description = "PutLoansLoanIdRequest")
|
||||
@@ -670,6 +822,16 @@ final class LoansApiResourceSwagger {
|
||||
|
||||
private PostLoansLoanIdRequest() {}
|
||||
|
||||
static final class PostLoansLoanIdDisbursementData {
|
||||
|
||||
private PostLoansLoanIdDisbursementData() {}
|
||||
|
||||
@Schema(example = "[2012, 4, 3]")
|
||||
public LocalDate expectedDisbursementDate;
|
||||
@Schema(example = "22000")
|
||||
public Double principal;
|
||||
}
|
||||
|
||||
@Schema(example = "2")
|
||||
public Integer toLoanOfficerId;
|
||||
@Schema(example = "02 September 2014")
|
||||
@@ -680,6 +842,24 @@ final class LoansApiResourceSwagger {
|
||||
public String dateFormat;
|
||||
@Schema(example = "")
|
||||
public Integer fromLoanOfficerId;
|
||||
@Schema(example = "3e7791ce-aa10-11ec-b909-0242ac120002")
|
||||
public String externalId;
|
||||
@Schema(example = "5000.33")
|
||||
public String transactionAmount;
|
||||
@Schema(example = "Description of disbursement details.")
|
||||
public String note;
|
||||
@Schema(example = "[2012, 4, 12]")
|
||||
public LocalDate actualDisbursementDate;
|
||||
@Schema(example = "3")
|
||||
public Integer paymentTypeId;
|
||||
@Schema(example = "[2012, 4, 3]")
|
||||
public LocalDate approvedOnDate;
|
||||
@Schema(example = "1000")
|
||||
public String approvedLoanAmount;
|
||||
@Schema(example = "[2012, 4, 10]")
|
||||
public LocalDate expectedDisbursementDate;
|
||||
@Schema(description = "List of PostLoansLoanIdDisbursementData")
|
||||
public List<PostLoansLoanIdDisbursementData> disbursementData;
|
||||
}
|
||||
|
||||
@Schema(description = "PostLoansLoanIdResponse")
|
||||
@@ -687,6 +867,50 @@ final class LoansApiResourceSwagger {
|
||||
|
||||
private PostLoansLoanIdResponse() {}
|
||||
|
||||
static final class PostLoansLoanIdStatus {
|
||||
|
||||
private PostLoansLoanIdStatus() {}
|
||||
|
||||
@Schema(example = "300")
|
||||
public Integer id;
|
||||
@Schema(example = "loanStatusType.approved")
|
||||
public String code;
|
||||
@Schema(example = "Approved")
|
||||
public String value;
|
||||
@Schema(example = "false")
|
||||
public Boolean pendingApproval;
|
||||
@Schema(example = "false")
|
||||
public Boolean waitingForDisbursal;
|
||||
@Schema(example = "true")
|
||||
public Boolean active;
|
||||
@Schema(example = "false")
|
||||
public Boolean closedObligationsMet;
|
||||
@Schema(example = "false")
|
||||
public Boolean closedWrittenOff;
|
||||
@Schema(example = "false")
|
||||
public Boolean closedRescheduled;
|
||||
@Schema(example = "false")
|
||||
public Boolean closed;
|
||||
@Schema(example = "false")
|
||||
public Boolean overpaid;
|
||||
}
|
||||
|
||||
static final class PostLoansLoanIdChanges {
|
||||
|
||||
private PostLoansLoanIdChanges() {}
|
||||
|
||||
@Schema(example = "en")
|
||||
public String locale;
|
||||
@Schema(example = "dd MMMM yyyy")
|
||||
public String dateFormat;
|
||||
@Schema(example = "[2012, 4, 3]")
|
||||
public LocalDate approvedOnDate;
|
||||
@Schema(example = "Loan approval note")
|
||||
public String note;
|
||||
@Schema(description = "PostLoansLoanIdStatus")
|
||||
public PostLoansLoanIdStatus status;
|
||||
}
|
||||
|
||||
@Schema(example = "2")
|
||||
public Integer officeId;
|
||||
@Schema(example = "6")
|
||||
@@ -695,5 +919,7 @@ final class LoansApiResourceSwagger {
|
||||
public Integer loanId;
|
||||
@Schema(example = "3")
|
||||
public Integer resourceId;
|
||||
@Schema(description = "PostLoansLoanIdChanges")
|
||||
public PostLoansLoanIdChanges changes;
|
||||
}
|
||||
}
|
||||
|
||||
+14
-2
@@ -45,6 +45,7 @@ import java.util.ListIterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
@@ -1953,7 +1954,7 @@ public class Loan extends AbstractPersistableCustom {
|
||||
|
||||
private void removeChargesByDisbursementID(Long id) {
|
||||
List<LoanCharge> tempCharges = new ArrayList<>();
|
||||
for (LoanCharge charge : this.charges) {
|
||||
for (LoanCharge charge : getCharges()) {
|
||||
LoanTrancheDisbursementCharge transCharge = charge.getTrancheDisbursementCharge();
|
||||
if (transCharge != null && id.equals(transCharge.getloanDisbursementDetails().getId())) {
|
||||
tempCharges.add(charge);
|
||||
@@ -1966,7 +1967,7 @@ public class Loan extends AbstractPersistableCustom {
|
||||
|
||||
private List<Long> fetchLoanTrancheChargeIds() {
|
||||
List<Long> list = new ArrayList<>();
|
||||
for (LoanCharge charge : this.charges) {
|
||||
for (LoanCharge charge : getCharges()) {
|
||||
if (charge.isTrancheDisbursementCharge() && charge.isActive()) {
|
||||
list.add(charge.getId());
|
||||
}
|
||||
@@ -6887,4 +6888,15 @@ public class Loan extends AbstractPersistableCustom {
|
||||
this.netDisbursalAmount = adjustedAmount.subtract(this.deriveSumTotalOfChargesDueAtDisbursement());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the charges.
|
||||
*
|
||||
* @return the charges
|
||||
*/
|
||||
public Collection<LoanCharge> getCharges() {
|
||||
// At the time of loan creation, "this.charges" will be null if no charges found in the request.
|
||||
// In that case, fetch loan (before commit) will return null for the charges.
|
||||
// Return empty set instead of null to avoid NPE
|
||||
return Optional.ofNullable(this.charges).orElse(new HashSet<>());
|
||||
}
|
||||
}
|
||||
|
||||
+4
-6
@@ -27,6 +27,7 @@ import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
@@ -53,13 +54,10 @@ import org.apache.fineract.portfolio.loanproduct.domain.LoanPreClosureInterestCa
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@Slf4j
|
||||
public final class LoanApplicationTerms {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LoanApplicationTerms.class);
|
||||
|
||||
private final ApplicationCurrency currency;
|
||||
|
||||
private final Calendar loanCalendar;
|
||||
@@ -675,7 +673,7 @@ public final class LoanApplicationTerms {
|
||||
case INVALID:
|
||||
break;
|
||||
case WHOLE_TERM:
|
||||
LOG.error("TODO Implement getPeriodEndDate for WHOLE_TERM");
|
||||
log.error("TODO Implement getPeriodEndDate for WHOLE_TERM");
|
||||
break;
|
||||
}
|
||||
return dueRepaymentPeriodDate;
|
||||
@@ -1080,7 +1078,7 @@ public final class LoanApplicationTerms {
|
||||
periodicInterestRate = oneDayOfYearInterestRate.multiply(numberOfDaysInPeriod, mc);
|
||||
break;
|
||||
case WHOLE_TERM:
|
||||
LOG.error("TODO Implement periodicInterestRate for WHOLE_TERM");
|
||||
log.error("TODO Implement periodicInterestRate for WHOLE_TERM");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
+1
-1
@@ -2109,7 +2109,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
+ " (SUM(COALESCE(mr.principal_completed_derived, 0)) " + " + SUM(COALESCE(mr.interest_completed_derived, 0)) "
|
||||
+ " + SUM(COALESCE(mr.fee_charges_completed_derived, 0)) "
|
||||
+ "+ SUM(COALESCE(mr.penalty_charges_completed_derived, 0))) > 0";
|
||||
BigDecimal bigDecimal = this.jdbcTemplate.queryForObject(sql, BigDecimal.class, new Object[] { loanId }); // NOSONAR
|
||||
BigDecimal bigDecimal = this.jdbcTemplate.queryForObject(sql, BigDecimal.class, loanId); // NOSONAR
|
||||
return new PaidInAdvanceData(bigDecimal);
|
||||
} catch (DataAccessException e) {
|
||||
return new PaidInAdvanceData(new BigDecimal(0));
|
||||
|
||||
+9
-2
@@ -546,7 +546,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
createStandingInstruction(loan);
|
||||
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
}
|
||||
|
||||
final Set<LoanCharge> loanCharges = loan.charges();
|
||||
@@ -585,9 +584,17 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BusinessEvents.LOAN_DISBURSAL,
|
||||
constructEntityMap(BusinessEntity.LOAN, loan));
|
||||
|
||||
Long entityId = loan.getId();
|
||||
|
||||
// During a disbursement, the entityId should be the disbursement transaction id
|
||||
if (!isAccountTransfer) {
|
||||
entityId = loan.getLoanTransactions().get(loan.getLoanTransactions().size() - 1).getId();
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(loan.getId()) //
|
||||
.withEntityId(entityId) //
|
||||
.withOfficeId(loan.getOfficeId()) //
|
||||
.withClientId(loan.getClientId()) //
|
||||
.withGroupId(loan.getGroupId()) //
|
||||
|
||||
+107
-14
@@ -21,8 +21,11 @@ package org.apache.fineract.portfolio.loanproduct.api;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper;
|
||||
import org.apache.fineract.portfolio.rate.data.RateData;
|
||||
|
||||
/**
|
||||
* Created by Chirag Gupta on 12/27/17.
|
||||
@@ -36,6 +39,36 @@ final class LoanProductsApiResourceSwagger {
|
||||
|
||||
private PostLoanProductsRequest() {}
|
||||
|
||||
static final class AllowAttributeOverrides {
|
||||
|
||||
private AllowAttributeOverrides() {}
|
||||
|
||||
@Schema(example = "true")
|
||||
public boolean amortizationType;
|
||||
@Schema(example = "true")
|
||||
public boolean interestType;
|
||||
@Schema(example = "true")
|
||||
public boolean transactionProcessingStrategyId;
|
||||
@Schema(example = "true")
|
||||
public boolean interestCalculationPeriodType;
|
||||
@Schema(example = "true")
|
||||
public boolean inArrearsTolerance;
|
||||
@Schema(example = "true")
|
||||
public boolean repaymentEvery;
|
||||
@Schema(example = "true")
|
||||
public boolean graceOnPrincipalAndInterestPayment;
|
||||
@Schema(example = "true")
|
||||
public boolean graceOnArrearsAgeing;
|
||||
}
|
||||
|
||||
static final class ChargeId {
|
||||
|
||||
private ChargeId() {}
|
||||
|
||||
@Schema(example = "1")
|
||||
public Integer id;
|
||||
}
|
||||
|
||||
@Schema(example = "LP Accrual Accounting")
|
||||
public String name;
|
||||
@Schema(example = "LPAA")
|
||||
@@ -98,6 +131,66 @@ final class LoanProductsApiResourceSwagger {
|
||||
public Integer overpaymentLiabilityAccountId;
|
||||
@Schema(example = "41")
|
||||
public Integer writeOffAccountId;
|
||||
@Schema(example = "false")
|
||||
public Boolean includeInBorrowerCycle;
|
||||
@Schema(example = "false")
|
||||
public Boolean useBorrowerCycle;
|
||||
@Schema(example = "[]")
|
||||
public List<Integer> principalVariationsForBorrowerCycle;
|
||||
@Schema(example = "[]")
|
||||
public List<Integer> interestRateVariationsForBorrowerCycle;
|
||||
@Schema(example = "[]")
|
||||
public List<Integer> numberOfRepaymentVariationsForBorrowerCycle;
|
||||
@Schema(example = "true")
|
||||
public Boolean multiDisburseLoan;
|
||||
@Schema(example = "0")
|
||||
public Integer interestRecalculationCompoundingMethod;
|
||||
@Schema(example = "2")
|
||||
public Integer rescheduleStrategyMethod;
|
||||
@Schema(example = "1")
|
||||
public Integer preClosureInterestCalculationStrategy;
|
||||
@Schema(example = "false")
|
||||
public Boolean isLinkedToFloatingInterestRates;
|
||||
@Schema(example = "false")
|
||||
public Boolean allowVariableInstallments;
|
||||
@Schema(example = "non-interest bearing product")
|
||||
public String description;
|
||||
@Schema(example = "1")
|
||||
public Integer installmentAmountInMultiplesOf;
|
||||
@Schema(example = "5000.000000")
|
||||
public Double minPrincipal;
|
||||
@Schema(example = "15000.000000")
|
||||
public Double maxPrincipal;
|
||||
@Schema(example = "30")
|
||||
public Integer minimumDaysBetweenDisbursalAndFirstRepayment;
|
||||
@Schema(example = "true")
|
||||
public Boolean allowPartialPeriodInterestCalcualtion;
|
||||
@Schema(example = "true")
|
||||
public Boolean disallowExpectedDisbursements;
|
||||
@Schema(example = "true")
|
||||
public Boolean allowApprovedDisbursedAmountsOverApplied;
|
||||
@Schema(example = "percentage")
|
||||
public String overAppliedCalculationType;
|
||||
@Schema(example = "50")
|
||||
public Integer overAppliedNumber;
|
||||
@Schema(example = "true")
|
||||
public Boolean canDefineInstallmentAmount;
|
||||
@Schema(example = "50")
|
||||
public Integer principalThresholdForLastInstallment;
|
||||
@Schema(example = "50")
|
||||
public Integer recalculationRestFrequencyType;
|
||||
@Schema(example = "3")
|
||||
public Integer maxTrancheCount;
|
||||
@Schema(example = "36000.000000")
|
||||
public Double outstandingLoanBalance;
|
||||
@Schema(example = "dd MMMM yyyy")
|
||||
public String dateFormat;
|
||||
public Set<GetLoanProductsProductIdResponse.GetLoanPaymentChannelToFundSourceMappings> paymentChannelToFundSourceMappings;
|
||||
public Set<GetLoanProductsProductIdResponse.GetLoanFeeToIncomeAccountMappings> feeToIncomeAccountMappings;
|
||||
public Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings;
|
||||
public AllowAttributeOverrides allowAttributeOverrides;
|
||||
public List<ChargeId> charges;
|
||||
public List<RateData> rates;
|
||||
}
|
||||
|
||||
@Schema(description = "PostLoanProductsResponse")
|
||||
@@ -313,11 +406,11 @@ final class LoanProductsApiResourceSwagger {
|
||||
public String status;
|
||||
public GetLoanProductsCurrency currency;
|
||||
@Schema(example = "10000.000000")
|
||||
public Float principal;
|
||||
public Double principal;
|
||||
@Schema(example = "5000.000000")
|
||||
public Float minPrincipal;
|
||||
public Double minPrincipal;
|
||||
@Schema(example = "15000.000000")
|
||||
public Float maxPrincipal;
|
||||
public Double maxPrincipal;
|
||||
@Schema(example = "10")
|
||||
public Integer numberOfRepayments;
|
||||
@Schema(example = "5")
|
||||
@@ -328,10 +421,10 @@ final class LoanProductsApiResourceSwagger {
|
||||
public Integer repaymentEvery;
|
||||
public GetLoanProductsRepaymentFrequencyType repaymentFrequencyType;
|
||||
@Schema(example = "15.000000")
|
||||
public Float interestRatePerPeriod;
|
||||
public Double interestRatePerPeriod;
|
||||
public GetLoanProductsResponse.GetLoanProductsInterestRateFrequencyType interestRateFrequencyType;
|
||||
@Schema(example = "15.000000")
|
||||
public Float annualInterestRate;
|
||||
public Double annualInterestRate;
|
||||
public GetLoanProductsAmortizationType amortizationType;
|
||||
@Schema(example = "5.5")
|
||||
public BigDecimal fixedPrincipalPercentagePerInstallment;
|
||||
@@ -862,11 +955,11 @@ final class LoanProductsApiResourceSwagger {
|
||||
public GetLoanProductsParamType paramType;
|
||||
public GetLoanProductsValueConditionType valueConditionType;
|
||||
@Schema(example = "2000.000000")
|
||||
public Float minValue;
|
||||
public Double minValue;
|
||||
@Schema(example = "20000.000000")
|
||||
public Float maxValue;
|
||||
public Double maxValue;
|
||||
@Schema(example = "15000.000000")
|
||||
public Float defaultValue;
|
||||
public Double defaultValue;
|
||||
}
|
||||
|
||||
static final class GetLoanAccountingMappings {
|
||||
@@ -1033,21 +1126,21 @@ final class LoanProductsApiResourceSwagger {
|
||||
public String status;
|
||||
public GetLoanProductsResponse.GetLoanProductsCurrency currency;
|
||||
@Schema(example = "10000.000000")
|
||||
public Float principal;
|
||||
public Double principal;
|
||||
@Schema(example = "2000.000000")
|
||||
public Float minPrincipal;
|
||||
public Double minPrincipal;
|
||||
@Schema(example = "15000.000000")
|
||||
public Float maxPrincipal;
|
||||
public Double maxPrincipal;
|
||||
@Schema(example = "7")
|
||||
public Integer numberOfRepayments;
|
||||
@Schema(example = "7")
|
||||
public Integer repaymentEvery;
|
||||
public GetLoanProductsResponse.GetLoanProductsRepaymentFrequencyType repaymentFrequencyType;
|
||||
@Schema(example = "5.000000")
|
||||
public Float interestRatePerPeriod;
|
||||
public Double interestRatePerPeriod;
|
||||
public GetLoanProductsProductIdResponse.GetLoanProductsInterestRateFrequencyType interestRateFrequencyType;
|
||||
@Schema(example = "60.000000")
|
||||
public Float annualInterestRate;
|
||||
public Double annualInterestRate;
|
||||
public GetLoanProductsResponse.GetLoanProductsAmortizationType amortizationType;
|
||||
@Schema(example = "5.5")
|
||||
public BigDecimal fixedPrincipalPercentagePerInstallment;
|
||||
@@ -1073,7 +1166,7 @@ final class LoanProductsApiResourceSwagger {
|
||||
@Schema(example = "3")
|
||||
public Integer maxTrancheCount;
|
||||
@Schema(example = "36000.000000")
|
||||
public Float outstandingLoanBalance;
|
||||
public Double outstandingLoanBalance;
|
||||
@Schema(example = "2")
|
||||
public Integer overdueDaysForNPA;
|
||||
@Schema(example = "50")
|
||||
|
||||
+2
@@ -197,6 +197,8 @@ final class SelfLoansApiResourceSwagger {
|
||||
public String disbursedByLastname;
|
||||
@Schema(example = "[2012, 4, 10]")
|
||||
public LocalDate expectedMaturityDate;
|
||||
@Schema(example = "[2012, 4, 3]")
|
||||
public LocalDate closedOnDate;
|
||||
}
|
||||
|
||||
static final class GetLoansLoanIdSummary {
|
||||
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* 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 static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
import javax.ws.rs.HttpMethod;
|
||||
import org.apache.fineract.batch.command.internal.ActivateClientCommandStrategy;
|
||||
import org.apache.fineract.batch.command.internal.ApplyLoanCommandStrategy;
|
||||
import org.apache.fineract.batch.command.internal.ApplySavingsCommandStrategy;
|
||||
import org.apache.fineract.batch.command.internal.ApproveLoanCommandStrategy;
|
||||
import org.apache.fineract.batch.command.internal.ApproveLoanRescheduleCommandStrategy;
|
||||
import org.apache.fineract.batch.command.internal.CollectChargesCommandStrategy;
|
||||
import org.apache.fineract.batch.command.internal.CreateChargeCommandStrategy;
|
||||
import org.apache.fineract.batch.command.internal.CreateClientCommandStrategy;
|
||||
import org.apache.fineract.batch.command.internal.DisburseLoanCommandStrategy;
|
||||
import org.apache.fineract.batch.command.internal.GetLoanByIdCommandStrategy;
|
||||
import org.apache.fineract.batch.command.internal.GetTransactionByIdCommandStrategy;
|
||||
import org.apache.fineract.batch.command.internal.RepayLoanCommandStrategy;
|
||||
import org.apache.fineract.batch.command.internal.UnknownCommandStrategy;
|
||||
import org.apache.fineract.batch.command.internal.UpdateClientCommandStrategy;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* Tests {@link CommandStrategyProvider}.
|
||||
*/
|
||||
public class CommandStrategyProviderTest {
|
||||
|
||||
/**
|
||||
* Command strategy provider.
|
||||
*
|
||||
* @return the test data stream
|
||||
*/
|
||||
private static Stream<Arguments> provideCommandStrategies() {
|
||||
return Stream.of(Arguments.of("clients", HttpMethod.POST, "createClientCommandStrategy", mock(CreateClientCommandStrategy.class)),
|
||||
Arguments.of("clients/123", HttpMethod.PUT, "updateClientCommandStrategy", mock(UpdateClientCommandStrategy.class)),
|
||||
Arguments.of("loans", HttpMethod.POST, "applyLoanCommandStrategy", mock(ApplyLoanCommandStrategy.class)),
|
||||
Arguments.of("loans/123", HttpMethod.GET, "getLoanByIdCommandStrategy", mock(GetLoanByIdCommandStrategy.class)),
|
||||
Arguments.of("loans/123?associations=all", HttpMethod.GET, "getLoanByIdCommandStrategy",
|
||||
mock(GetLoanByIdCommandStrategy.class)),
|
||||
Arguments.of("loans/123?associations=all&exclude=guarantors", HttpMethod.GET, "getLoanByIdCommandStrategy",
|
||||
mock(GetLoanByIdCommandStrategy.class)),
|
||||
Arguments.of("savingsaccounts", HttpMethod.POST, "applySavingsCommandStrategy", mock(ApplySavingsCommandStrategy.class)),
|
||||
Arguments.of("loans/123/charges", HttpMethod.POST, "createChargeCommandStrategy", mock(CreateChargeCommandStrategy.class)),
|
||||
Arguments.of("loans/123/charges", HttpMethod.GET, "collectChargesCommandStrategy",
|
||||
mock(CollectChargesCommandStrategy.class)),
|
||||
Arguments.of("loans/123/transactions?command=repayment", HttpMethod.POST, "repayLoanCommandStrategy",
|
||||
mock(RepayLoanCommandStrategy.class)),
|
||||
Arguments.of("clients/456?command=activate", HttpMethod.POST, "activateClientCommandStrategy",
|
||||
mock(ActivateClientCommandStrategy.class)),
|
||||
Arguments.of("loans/123?command=approve", HttpMethod.POST, "approveLoanCommandStrategy",
|
||||
mock(ApproveLoanCommandStrategy.class)),
|
||||
Arguments.of("loans/123?command=disburse", HttpMethod.POST, "disburseLoanCommandStrategy",
|
||||
mock(DisburseLoanCommandStrategy.class)),
|
||||
Arguments.of("rescheduleloans/123?command=approve", HttpMethod.POST, "approveLoanRescheduleCommandStrategy",
|
||||
mock(ApproveLoanRescheduleCommandStrategy.class)),
|
||||
Arguments.of("loans/123/transactions/123", HttpMethod.GET, "getTransactionByIdCommandStrategy",
|
||||
mock(GetTransactionByIdCommandStrategy.class)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link CommandStrategyProvider#getCommandStrategy} for success scenarios.
|
||||
*
|
||||
* @param url
|
||||
* the resource URL
|
||||
* @param httpMethod
|
||||
* the resource HTTP method
|
||||
* @param beanName
|
||||
* the context bean name
|
||||
* @param commandStrategy
|
||||
* the command strategy
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideCommandStrategies")
|
||||
public void testGetCommandStrategySuccess(final String url, final String httpMethod, final String beanName,
|
||||
final CommandStrategy commandStrategy) {
|
||||
final ApplicationContext applicationContext = mock(ApplicationContext.class);
|
||||
final CommandStrategyProvider commandStrategyProvider = new CommandStrategyProvider(applicationContext);
|
||||
when(applicationContext.getBean(beanName)).thenReturn(commandStrategy);
|
||||
|
||||
final CommandStrategy result = commandStrategyProvider.getCommandStrategy(CommandContext.resource(url).method(httpMethod).build());
|
||||
assertEquals(commandStrategy, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Command strategy provider for error scenarioss.
|
||||
*
|
||||
* @return the test data stream
|
||||
*/
|
||||
private static Stream<Arguments> provideCommandStrategyResourceDetailsForErrors() {
|
||||
return Stream.of(Arguments.of("loans/123?command=reject", HttpMethod.POST),
|
||||
Arguments.of("loans/glimAccount/746?command=approve", HttpMethod.POST), Arguments.of("loans/123", HttpMethod.PUT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link CommandStrategyProvider#getCommandStrategy} for error scenarios.
|
||||
*
|
||||
* @param url
|
||||
* the resource URL
|
||||
* @param httpMethod
|
||||
* the resource HTTP method
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideCommandStrategyResourceDetailsForErrors")
|
||||
public void testGetCommandStrategyForError(final String url, final String httpMethod) {
|
||||
final ApplicationContext applicationContext = mock(ApplicationContext.class);
|
||||
final CommandStrategyProvider commandStrategyProvider = new CommandStrategyProvider(applicationContext);
|
||||
|
||||
final CommandStrategy result = commandStrategyProvider.getCommandStrategy(CommandContext.resource(url).method(httpMethod).build());
|
||||
assertEquals(UnknownCommandStrategy.class, result.getClass());
|
||||
}
|
||||
}
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
* 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.internal;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
import javax.ws.rs.HttpMethod;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.apache.fineract.batch.domain.BatchRequest;
|
||||
import org.apache.fineract.batch.domain.BatchResponse;
|
||||
import org.apache.fineract.infrastructure.core.api.MutableUriInfo;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoansApiResource;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
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.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
public class GetLoanByIdCommandStrategyTest {
|
||||
|
||||
private static Stream<Arguments> provideQueryParameters() {
|
||||
return Stream.of(Arguments.of(null, 0), Arguments.of("associations=all", 1),
|
||||
Arguments.of("fields=id,principal,annualInterestRate&associations=repaymentSchedule,transactions", 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link GetLoanByIdCommandStrategy#execute} happy path scenario.
|
||||
*
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideQueryParameters")
|
||||
public void testExecuteSuccessScenario(final String queryParameter, final int noOfQueryParams) {
|
||||
// given
|
||||
final TestContext testContext = new TestContext();
|
||||
|
||||
final Long loanId = Long.valueOf(RandomStringUtils.randomNumeric(4));
|
||||
final BatchRequest request = getBatchRequest(loanId, queryParameter);
|
||||
final String responseBody = "{\\\"id\\\":2,\\\"accountNo\\\":\\\"000000002\\\"}";
|
||||
|
||||
given(testContext.loansApiResource.retrieveLoan(eq(loanId), eq(false), any(UriInfo.class))).willReturn(responseBody);
|
||||
|
||||
// when
|
||||
final BatchResponse response = testContext.underTest.execute(request, testContext.uriInfo);
|
||||
|
||||
// then
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
|
||||
assertThat(response.getRequestId()).isEqualTo(request.getRequestId());
|
||||
assertThat(response.getHeaders()).isEqualTo(request.getHeaders());
|
||||
assertThat(response.getBody()).isEqualTo(responseBody);
|
||||
|
||||
verify(testContext.loansApiResource).retrieveLoan(eq(loanId), eq(false), testContext.uriInfoCaptor.capture());
|
||||
MutableUriInfo mutableUriInfo = testContext.uriInfoCaptor.getValue();
|
||||
assertThat(mutableUriInfo.getAdditionalQueryParameters()).hasSize(noOfQueryParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link GetLoanByIdCommandStrategy#execute} for internal server error.
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteForInternalServerError() {
|
||||
// given
|
||||
final TestContext testContext = new TestContext();
|
||||
final Long loanId = Long.valueOf(RandomStringUtils.randomNumeric(4));
|
||||
final BatchRequest request = getBatchRequest(loanId, null);
|
||||
|
||||
given(testContext.loansApiResource.retrieveLoan(eq(loanId), eq(false), any(UriInfo.class)))
|
||||
.willThrow(new RuntimeException("Some error"));
|
||||
|
||||
// when
|
||||
final BatchResponse response = testContext.underTest.execute(request, testContext.uriInfo);
|
||||
|
||||
// then
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SC_INTERNAL_SERVER_ERROR);
|
||||
assertThat(response.getBody()).isEqualTo("{\"Exception\": java.lang.RuntimeException: Some error}");
|
||||
assertThat(response.getRequestId()).isEqualTo(request.getRequestId());
|
||||
assertThat(response.getHeaders()).isEqualTo(request.getHeaders());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link GetLoanByIdCommandStrategy#execute} for loan not found exception.
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteForLoanNotFoundException() {
|
||||
// given
|
||||
final TestContext testContext = new TestContext();
|
||||
final Long loanId = Long.valueOf(RandomStringUtils.randomNumeric(4));
|
||||
final BatchRequest request = getBatchRequest(loanId, null);
|
||||
|
||||
given(testContext.loansApiResource.retrieveLoan(eq(loanId), eq(false), any(UriInfo.class)))
|
||||
.willThrow(new LoanNotFoundException(loanId));
|
||||
|
||||
// when
|
||||
final BatchResponse response = testContext.underTest.execute(request, testContext.uriInfo);
|
||||
|
||||
// then
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SC_NOT_FOUND);
|
||||
assertThat(response.getBody()).isEqualTo(buildLoanNotFoundError(loanId));
|
||||
assertThat(response.getRequestId()).isEqualTo(request.getRequestId());
|
||||
assertThat(response.getHeaders()).isEqualTo(request.getHeaders());
|
||||
}
|
||||
|
||||
private String buildLoanNotFoundError(final Long loanId) {
|
||||
return String.format(
|
||||
"{\n \"developerMessage\": \"The requested resource is not available.\",\n"
|
||||
+ " \"httpStatusCode\": \"404\",\n \"defaultUserMessage\": \"The requested resource is not available.\",\n"
|
||||
+ " \"userMessageGlobalisationCode\": \"error.msg.resource.not.found\",\n \"errors\": [\n {\n"
|
||||
+ " \"developerMessage\": \"Loan with identifier %s does not exist\",\n"
|
||||
+ " \"defaultUserMessage\": \"Loan with identifier %s does not exist\",\n"
|
||||
+ " \"userMessageGlobalisationCode\": \"error.msg.loan.id.invalid\",\n \"parameterName\": \"id\",\n"
|
||||
+ " \"args\": [\n {\n \"value\": %s\n }\n ]\n }\n ]\n" + "}",
|
||||
loanId, loanId, loanId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a request with the given loan id.
|
||||
*
|
||||
* @param loanId
|
||||
* the loan id
|
||||
* @return BatchRequest
|
||||
*/
|
||||
private BatchRequest getBatchRequest(final Long loanId, final String queryParamStr) {
|
||||
|
||||
final BatchRequest br = new BatchRequest();
|
||||
String relativeUrl = "loans/" + loanId;
|
||||
if (queryParamStr != null) {
|
||||
relativeUrl = relativeUrl + "?" + queryParamStr;
|
||||
}
|
||||
|
||||
br.setRequestId(Long.valueOf(RandomStringUtils.randomNumeric(5)));
|
||||
br.setRelativeUrl(relativeUrl);
|
||||
br.setMethod(HttpMethod.GET);
|
||||
br.setReference(Long.valueOf(RandomStringUtils.randomNumeric(5)));
|
||||
br.setBody("{}");
|
||||
|
||||
return br;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private test context class used since testng runs in parallel to avoid state between tests
|
||||
*/
|
||||
private static class TestContext {
|
||||
|
||||
@Mock
|
||||
private UriInfo uriInfo;
|
||||
|
||||
@Mock
|
||||
private LoansApiResource loansApiResource;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<MutableUriInfo> uriInfoCaptor;
|
||||
|
||||
private final GetLoanByIdCommandStrategy underTest;
|
||||
|
||||
TestContext() {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
underTest = new GetLoanByIdCommandStrategy(loansApiResource);
|
||||
}
|
||||
}
|
||||
}
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* 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.internal;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import javax.ws.rs.HttpMethod;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.apache.fineract.batch.domain.BatchRequest;
|
||||
import org.apache.fineract.batch.domain.BatchResponse;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanTransactionsApiResource;
|
||||
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.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
public class GetTransactionByIdCommandStrategyTest {
|
||||
|
||||
/**
|
||||
* Test {@link GetTransactionByIdCommandStrategy#execute} happy path scenario.
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteSuccessScenario() {
|
||||
// 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 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,"
|
||||
+ "\"recoveryRepayment\":false,\"initiateTransfer\":false,\"approveTransfer\":false,\"withdrawTransfer\":false,"
|
||||
+ "\"rejectTransfer\":false,\"chargePayment\":false,\"refund\":false,\"refundForActiveLoans\":false},\"date\":[2022,3,29],"
|
||||
+ "\"currency\":{\"code\":\"EUR\",\"name\":\"Euro\",\"decimalPlaces\":2,\"inMultiplesOf\":0,\"displaySymbol\":\"€\","
|
||||
+ "\"nameCode\":\"currency.EUR\",\"displayLabel\":\"Euro (€)\"},\"amount\":0.000000,\"netDisbursalAmount\":200.000000,"
|
||||
+ "\"principalPortion\":0,\"interestPortion\":0.000000,\"feeChargesPortion\":0,\"penaltyChargesPortion\":0,\"overpaymentPortion\":0,"
|
||||
+ "\"unrecognizedIncomePortion\":0,\"outstandingLoanBalance\":0,\"submittedOnDate\":[2022,3,29],\"manuallyReversed\":false,"
|
||||
+ "\"loanChargePaidByList\":[],\"numberOfRepayments\":0}";
|
||||
|
||||
given(testContext.loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, testContext.uriInfo))
|
||||
.willReturn(responseBody);
|
||||
|
||||
// when
|
||||
final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo);
|
||||
|
||||
// then
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
|
||||
assertThat(response.getRequestId()).isEqualTo(request.getRequestId());
|
||||
assertThat(response.getHeaders()).isEqualTo(request.getHeaders());
|
||||
assertThat(response.getBody()).isEqualTo(responseBody);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link GetTransactionByIdCommandStrategy#execute} for internal server error.
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteForInternalServerError() {
|
||||
// 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);
|
||||
|
||||
given(testContext.loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, testContext.uriInfo))
|
||||
.willThrow(new RuntimeException("Some error"));
|
||||
|
||||
// when
|
||||
final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo);
|
||||
|
||||
// then
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SC_INTERNAL_SERVER_ERROR);
|
||||
assertThat(response.getRequestId()).isEqualTo(request.getRequestId());
|
||||
assertThat(response.getHeaders()).isEqualTo(request.getHeaders());
|
||||
assertThat(response.getBody()).isEqualTo("{\"Exception\": java.lang.RuntimeException: Some error}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link GetTransactionByIdCommandStrategy#execute} for loan not found exception.
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteForLoanNotFoundException() {
|
||||
// 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);
|
||||
|
||||
given(testContext.loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, testContext.uriInfo))
|
||||
.willThrow(new LoanNotFoundException(loanId));
|
||||
|
||||
// when
|
||||
final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo);
|
||||
|
||||
// then
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SC_NOT_FOUND);
|
||||
assertThat(response.getRequestId()).isEqualTo(request.getRequestId());
|
||||
assertThat(response.getHeaders()).isEqualTo(request.getHeaders());
|
||||
assertThat(response.getBody()).isEqualTo(build404NotFoundError("Loan", loanId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link GetTransactionByIdCommandStrategy#execute} for transaction not found exception.
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteForTransactionNotFoundException() {
|
||||
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);
|
||||
|
||||
when(testContext.loanTransactionsApiResource.retrieveTransaction(loanId, transactionId, testContext.uriInfo))
|
||||
.thenThrow(new LoanTransactionNotFoundException(transactionId));
|
||||
|
||||
final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo);
|
||||
|
||||
assertEquals(HttpStatus.SC_NOT_FOUND, response.getStatusCode());
|
||||
assertEquals(build404NotFoundError("Transaction", transactionId), response.getBody());
|
||||
assertEquals(request.getRequestId(), response.getRequestId());
|
||||
assertEquals(request.getHeaders(), response.getHeaders());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a request with the given loan id and transaction id.
|
||||
*
|
||||
* @param loanId
|
||||
* the loan id
|
||||
* @param transactionId
|
||||
* the transaction id
|
||||
* @return BatchRequest
|
||||
*/
|
||||
private BatchRequest getBatchRequest(final Long loanId, final Long transactionId) {
|
||||
|
||||
final BatchRequest br = new BatchRequest();
|
||||
String relativeUrl = "loans/" + loanId + "/transactions/" + transactionId;
|
||||
|
||||
br.setRequestId(Long.valueOf(RandomStringUtils.randomNumeric(5)));
|
||||
br.setRelativeUrl(relativeUrl);
|
||||
br.setMethod(HttpMethod.GET);
|
||||
br.setReference(Long.valueOf(RandomStringUtils.randomNumeric(5)));
|
||||
br.setBody("{}");
|
||||
|
||||
return br;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the 404 not found error.
|
||||
*
|
||||
* @param field
|
||||
* the field name
|
||||
* @param id
|
||||
* the id
|
||||
*/
|
||||
private String build404NotFoundError(final String field, final Long id) {
|
||||
return String.format("{\n" + " \"developerMessage\": \"The requested resource is not available.\",\n"
|
||||
+ " \"httpStatusCode\": \"404\",\n" + " \"defaultUserMessage\": \"The requested resource is not available.\",\n"
|
||||
+ " \"userMessageGlobalisationCode\": \"error.msg.resource.not.found\",\n" + " \"errors\": [\n" + " {\n"
|
||||
+ " \"developerMessage\": \"%s with identifier %s does not exist\",\n"
|
||||
+ " \"defaultUserMessage\": \"%s with identifier %s does not exist\",\n"
|
||||
+ " \"userMessageGlobalisationCode\": \"error.msg.loan.id.invalid\",\n" + " \"parameterName\": \"id\",\n"
|
||||
+ " \"args\": [\n" + " {\n" + " \"value\": %s\n" + " }\n" + " ]\n" + " }\n" + " ]\n"
|
||||
+ "}", field, id, field, id, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private test context class used since testng runs in parallel to avoid state between tests
|
||||
*/
|
||||
private static class TestContext {
|
||||
|
||||
@Mock
|
||||
private UriInfo uriInfo;
|
||||
|
||||
@Mock
|
||||
private LoanTransactionsApiResource loanTransactionsApiResource;
|
||||
|
||||
private final GetTransactionByIdCommandStrategy subjectToTest;
|
||||
|
||||
TestContext() {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
subjectToTest = new GetTransactionByIdCommandStrategy(loanTransactionsApiResource);
|
||||
}
|
||||
}
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* 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.portfolio.loanaccount.domain;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
/**
|
||||
* Tests {@link Loan}.
|
||||
*/
|
||||
public class LoanTest {
|
||||
|
||||
/**
|
||||
* Tests {@link Loan#getCharges()} with charges.
|
||||
*/
|
||||
@Test
|
||||
public void testGetChargesWithCharges() {
|
||||
Loan loan = new Loan();
|
||||
ReflectionTestUtils.setField(loan, "charges", Collections.singleton(buildLoanCharge()));
|
||||
|
||||
final Collection<LoanCharge> chargeIds = loan.getCharges();
|
||||
|
||||
assertEquals(1, chargeIds.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link Loan#getCharges()} with no charges.
|
||||
*/
|
||||
@Test
|
||||
public void testGetChargesWithNoCharges() {
|
||||
final Loan loan = new Loan();
|
||||
|
||||
final Collection<LoanCharge> chargeIds = loan.getCharges();
|
||||
|
||||
assertEquals(0, chargeIds.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link Loan#getCharges()} with null to make sure NPE is not thrown.
|
||||
*/
|
||||
@Test
|
||||
public void testGetChargesWithNull() {
|
||||
final Loan loan = new Loan();
|
||||
ReflectionTestUtils.setField(loan, "charges", null);
|
||||
|
||||
final Collection<LoanCharge> chargeIds = loan.getCharges();
|
||||
|
||||
assertEquals(0, chargeIds.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a new loan charge.
|
||||
*
|
||||
* @return the {@link LoanCharge}
|
||||
*/
|
||||
private LoanCharge buildLoanCharge() {
|
||||
return new LoanCharge(mock(Loan.class), mock(Charge.class), new BigDecimal(100), new BigDecimal(100),
|
||||
ChargeTimeType.TRANCHE_DISBURSEMENT, ChargeCalculationType.FLAT, DateUtils.getLocalDateOfTenant(),
|
||||
ChargePaymentMode.REGULAR, 1, new BigDecimal(100));
|
||||
}
|
||||
}
|
||||
+200
-7
@@ -38,6 +38,8 @@ import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
|
||||
import org.apache.fineract.integrationtests.common.savings.SavingsProductHelper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -115,7 +117,7 @@ public class BatchApiTest {
|
||||
* rolled back.
|
||||
*
|
||||
* @see org.apache.fineract.batch.command.internal.CreateClientCommandStrategy
|
||||
* @see org.apache.fineract.batch.api.BatchApiResource
|
||||
* @see org.apache.fineract.batch.api.BatchesApiResource
|
||||
* @see org.apache.fineract.batch.service.BatchApiService
|
||||
*/
|
||||
@Test
|
||||
@@ -426,7 +428,7 @@ public class BatchApiTest {
|
||||
// Create a createClient Request
|
||||
final BatchRequest br1 = BatchHelper.createClientRequest(4726L, "");
|
||||
|
||||
// Create a activateClient Request
|
||||
// Create an activateClient Request
|
||||
final BatchRequest br2 = BatchHelper.activateClientRequest(4727L, 4726L);
|
||||
|
||||
final List<BatchRequest> batchRequests = new ArrayList<>();
|
||||
@@ -480,13 +482,13 @@ public class BatchApiTest {
|
||||
// Create a activateClient Request
|
||||
final BatchRequest br2 = BatchHelper.activateClientRequest(4731L, 4730L);
|
||||
|
||||
// Create a ApplyLoan Request
|
||||
// Create an ApplyLoan Request
|
||||
final BatchRequest br3 = BatchHelper.applyLoanRequest(4732L, 4731L, productId, clientCollateralId);
|
||||
|
||||
// Create a approveLoan Request
|
||||
// Create an approveLoan Request
|
||||
final BatchRequest br4 = BatchHelper.approveLoanRequest(4733L, 4732L);
|
||||
|
||||
// Create a disburseLoan Request
|
||||
// Create an disburseLoan Request
|
||||
final BatchRequest br5 = BatchHelper.disburseLoanRequest(4734L, 4733L);
|
||||
|
||||
final List<BatchRequest> batchRequests = new ArrayList<>();
|
||||
@@ -540,10 +542,10 @@ public class BatchApiTest {
|
||||
// Create a createClient Request
|
||||
final BatchRequest br1 = BatchHelper.createActiveClientRequest(4740L, "");
|
||||
|
||||
// Create a ApplyLoan Request
|
||||
// Create an ApplyLoan Request
|
||||
final BatchRequest br2 = BatchHelper.applyLoanRequest(4742L, 4740L, productId, clientCollateralId);
|
||||
|
||||
// Create a approveLoan Request
|
||||
// Create an approveLoan Request
|
||||
final BatchRequest br3 = BatchHelper.approveLoanRequest(4743L, 4742L);
|
||||
|
||||
// Create a disburseLoan Request
|
||||
@@ -561,4 +563,195 @@ public class BatchApiTest {
|
||||
Assertions.assertEquals(200L, (long) response.get(2).getStatusCode(), "Verify Status Code 200 for approve Loan");
|
||||
Assertions.assertEquals(200L, (long) response.get(3).getStatusCode(), "Verify Status Code 200 for disburse Loan");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@Test
|
||||
public void shouldReturnOkStatusOnSuccessfulDisbursementAndGetTransaction() {
|
||||
final String loanProductJSON = new LoanProductTestBuilder() //
|
||||
.withPrincipal("10000000.00") //
|
||||
.withNumberOfRepayments("24") //
|
||||
.withRepaymentAfterEvery("1") //
|
||||
.withRepaymentTypeAsMonth() //
|
||||
.withinterestRatePerPeriod("2") //
|
||||
.withInterestRateFrequencyTypeAsMonths() //
|
||||
.withAmortizationTypeAsEqualPrincipalPayment() //
|
||||
.withInterestTypeAsDecliningBalance() //
|
||||
.currencyDetails("0", "100").build(null);
|
||||
|
||||
final Long applyLoanRequestId = 6730L;
|
||||
final Long approveLoanRequestId = 6731L;
|
||||
final Long disburseLoanRequestId = 6732L;
|
||||
final Long getTransactionRequestId = 6733L;
|
||||
|
||||
// Create product
|
||||
final Integer productId = new LoanTransactionHelper(this.requestSpec, this.responseSpec).getLoanProductId(loanProductJSON);
|
||||
|
||||
// Create client
|
||||
final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientId);
|
||||
|
||||
// Create an ApplyLoan Request
|
||||
final BatchRequest batchRequest1 = BatchHelper.applyLoanRequestWithClientId(applyLoanRequestId, clientId, productId);
|
||||
|
||||
// Create an approveLoan Request
|
||||
final BatchRequest batchRequest2 = BatchHelper.approveLoanRequest(approveLoanRequestId, applyLoanRequestId);
|
||||
|
||||
// Create a disbursement Request
|
||||
final BatchRequest batchRequest3 = BatchHelper.disburseLoanRequest(disburseLoanRequestId, approveLoanRequestId);
|
||||
|
||||
// Create a getTransaction Request
|
||||
final BatchRequest batchRequest4 = BatchHelper.getTransactionByIdRequest(getTransactionRequestId, disburseLoanRequestId);
|
||||
|
||||
final List<BatchRequest> batchRequests = Arrays.asList(batchRequest1, batchRequest2, batchRequest3, batchRequest4);
|
||||
|
||||
final List<BatchResponse> responses = BatchHelper.postBatchRequestsWithoutEnclosingTransaction(this.requestSpec, this.responseSpec,
|
||||
BatchHelper.toJsonString(batchRequests));
|
||||
|
||||
Assertions.assertEquals(HttpStatus.SC_OK, responses.get(0).getStatusCode(), "Verify Status Code 200 for Apply Loan");
|
||||
Assertions.assertEquals(HttpStatus.SC_OK, responses.get(1).getStatusCode(), "Verify Status Code 200 for Approve Loan");
|
||||
Assertions.assertEquals(HttpStatus.SC_OK, responses.get(2).getStatusCode(), "Verify Status Code 200 for Disburse Loan");
|
||||
Assertions.assertEquals(HttpStatus.SC_OK, responses.get(3).getStatusCode(), "Verify Status Code 200 for Get Transaction By Id");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for the successful create client, creat, approve and get loan. A '200' status code is expected on successful
|
||||
* responses.
|
||||
*
|
||||
* @see org.apache.fineract.batch.command.internal.CreateClientCommandStrategy
|
||||
* @see org.apache.fineract.batch.command.internal.ApplyLoanCommandStrategy
|
||||
* @see org.apache.fineract.batch.command.internal.ApproveLoanCommandStrategy
|
||||
* @see org.apache.fineract.batch.command.internal.GetLoanByIdCommandStrategy
|
||||
*/
|
||||
@Test
|
||||
public void shouldReturnOkStatusOnSuccessfulCreateClientCreateApproveAndGetLoan() {
|
||||
final String loanProductJSON = new LoanProductTestBuilder() //
|
||||
.withPrincipal("10000000.00") //
|
||||
.withNumberOfRepayments("24") //
|
||||
.withRepaymentAfterEvery("1") //
|
||||
.withRepaymentTypeAsMonth() //
|
||||
.withinterestRatePerPeriod("2") //
|
||||
.withInterestRateFrequencyTypeAsMonths() //
|
||||
.withAmortizationTypeAsEqualPrincipalPayment() //
|
||||
.withInterestTypeAsDecliningBalance() //
|
||||
.currencyDetails("0", "100").build(null);
|
||||
|
||||
final Long createActiveClientRequestId = 4730L;
|
||||
final Long applyLoanRequestId = 4731L;
|
||||
final Long approveLoanRequestId = 4732L;
|
||||
final Long getLoanByIdRequestId = 4733L;
|
||||
|
||||
// Create product
|
||||
final Integer productId = new LoanTransactionHelper(this.requestSpec, this.responseSpec).getLoanProductId(loanProductJSON);
|
||||
|
||||
// Create createClient Request
|
||||
final BatchRequest batchRequest1 = BatchHelper.createActiveClientRequest(createActiveClientRequestId, "");
|
||||
|
||||
// Create an ApplyLoan Request
|
||||
final BatchRequest batchRequest2 = BatchHelper.applyLoanRequest(applyLoanRequestId, createActiveClientRequestId, productId, null);
|
||||
|
||||
// Create an approveLoan Request
|
||||
final BatchRequest batchRequest3 = BatchHelper.approveLoanRequest(approveLoanRequestId, applyLoanRequestId);
|
||||
|
||||
// Get loan by id Request
|
||||
final BatchRequest batchRequest4 = BatchHelper.getLoanByIdRequest(getLoanByIdRequestId, applyLoanRequestId, null);
|
||||
|
||||
final List<BatchRequest> batchRequests = Arrays.asList(batchRequest1, batchRequest2, batchRequest3, batchRequest4);
|
||||
|
||||
final List<BatchResponse> responses = BatchHelper.postBatchRequestsWithEnclosingTransaction(this.requestSpec, this.responseSpec,
|
||||
BatchHelper.toJsonString(batchRequests));
|
||||
|
||||
Assertions.assertEquals(HttpStatus.SC_OK, responses.get(0).getStatusCode(), "Verify Status Code 200 for Create Client");
|
||||
Assertions.assertEquals(HttpStatus.SC_OK, responses.get(1).getStatusCode(), "Verify Status Code 200 for Apply Loan");
|
||||
Assertions.assertEquals(HttpStatus.SC_OK, responses.get(2).getStatusCode(), "Verify Status Code 200 for Approve Loan");
|
||||
Assertions.assertEquals(HttpStatus.SC_OK, responses.get(3).getStatusCode(), "Verify Status Code 200 for Get Loan By Id");
|
||||
|
||||
final FromJsonHelper jsonHelper = new FromJsonHelper();
|
||||
final Long loanId = jsonHelper.extractLongNamed("loanId", jsonHelper.parse(responses.get(1).getBody()).getAsJsonObject());
|
||||
final Long loanIdInGetResponse = jsonHelper.extractLongNamed("id", jsonHelper.parse(responses.get(3).getBody()).getAsJsonObject());
|
||||
final JsonObject statusInGetResponse = jsonHelper.parse(responses.get(3).getBody()).getAsJsonObject().get("status")
|
||||
.getAsJsonObject();
|
||||
|
||||
Assertions.assertEquals(loanId, loanIdInGetResponse);
|
||||
Assertions.assertEquals(LoanStatus.APPROVED.getCode(), jsonHelper.extractStringNamed("code", statusInGetResponse));
|
||||
Assertions.assertEquals("Approved", jsonHelper.extractStringNamed("value", statusInGetResponse));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for the successful creat, approve and get loan. A '200' status code is expected on successful responses.
|
||||
*
|
||||
* @see org.apache.fineract.batch.command.internal.ApplyLoanCommandStrategy
|
||||
* @see org.apache.fineract.batch.command.internal.ApproveLoanCommandStrategy
|
||||
* @see org.apache.fineract.batch.command.internal.GetLoanByIdCommandStrategy
|
||||
*/
|
||||
@Test
|
||||
public void shouldReturnOkStatusOnSuccessfulCreateApproveAndGetLoan() {
|
||||
final String loanProductJSON = new LoanProductTestBuilder() //
|
||||
.withPrincipal("10000000.00") //
|
||||
.withNumberOfRepayments("24") //
|
||||
.withRepaymentAfterEvery("1") //
|
||||
.withRepaymentTypeAsMonth() //
|
||||
.withinterestRatePerPeriod("2") //
|
||||
.withInterestRateFrequencyTypeAsMonths() //
|
||||
.withAmortizationTypeAsEqualPrincipalPayment() //
|
||||
.withInterestTypeAsDecliningBalance() //
|
||||
.currencyDetails("0", "100").build(null);
|
||||
|
||||
final Long applyLoanRequestId = 5730L;
|
||||
final Long approveLoanRequestId = 5731L;
|
||||
final Long getLoanByIdRequestId = 5732L;
|
||||
final Long getLoanByIdWithQueryParametersRequestId = 5733L;
|
||||
|
||||
// Create product
|
||||
final Integer productId = new LoanTransactionHelper(this.requestSpec, this.responseSpec).getLoanProductId(loanProductJSON);
|
||||
|
||||
// Create client
|
||||
final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientId);
|
||||
|
||||
// Create an ApplyLoan Request
|
||||
final BatchRequest batchRequest1 = BatchHelper.applyLoanRequestWithClientId(applyLoanRequestId, clientId, productId);
|
||||
|
||||
// Create an approveLoan Request
|
||||
final BatchRequest batchRequest2 = BatchHelper.approveLoanRequest(approveLoanRequestId, applyLoanRequestId);
|
||||
|
||||
// Get loan by id Request without query param
|
||||
final BatchRequest batchRequest3 = BatchHelper.getLoanByIdRequest(getLoanByIdRequestId, applyLoanRequestId, null);
|
||||
|
||||
// Get loan by id Request with query param
|
||||
final BatchRequest batchRequest4 = BatchHelper.getLoanByIdRequest(getLoanByIdWithQueryParametersRequestId, applyLoanRequestId,
|
||||
"associations=repaymentSchedule,transactions");
|
||||
|
||||
final List<BatchRequest> batchRequests = Arrays.asList(batchRequest1, batchRequest2, batchRequest3, batchRequest4);
|
||||
|
||||
final List<BatchResponse> responses = BatchHelper.postBatchRequestsWithEnclosingTransaction(this.requestSpec, this.responseSpec,
|
||||
BatchHelper.toJsonString(batchRequests));
|
||||
|
||||
Assertions.assertEquals(HttpStatus.SC_OK, responses.get(0).getStatusCode(), "Verify Status Code 200 for Apply Loan");
|
||||
Assertions.assertEquals(HttpStatus.SC_OK, responses.get(1).getStatusCode(), "Verify Status Code 200 for Approve Loan");
|
||||
Assertions.assertEquals(HttpStatus.SC_OK, responses.get(2).getStatusCode(),
|
||||
"Verify Status Code 200 for Get Loan By Id without query parameter");
|
||||
Assertions.assertEquals(HttpStatus.SC_OK, responses.get(3).getStatusCode(),
|
||||
"Verify Status Code 200 for Get Loan By Id with query parameter");
|
||||
|
||||
final FromJsonHelper jsonHelper = new FromJsonHelper();
|
||||
final Long loanId = jsonHelper.extractLongNamed("loanId", jsonHelper.parse(responses.get(0).getBody()).getAsJsonObject());
|
||||
final Long loanIdInGetResponse = jsonHelper.extractLongNamed("id", jsonHelper.parse(responses.get(2).getBody()).getAsJsonObject());
|
||||
final JsonObject statusInGetResponse = jsonHelper.parse(responses.get(2).getBody()).getAsJsonObject().get("status")
|
||||
.getAsJsonObject();
|
||||
|
||||
Assertions.assertEquals(loanId, loanIdInGetResponse);
|
||||
Assertions.assertEquals(LoanStatus.APPROVED.getCode(), jsonHelper.extractStringNamed("code", statusInGetResponse));
|
||||
Assertions.assertEquals("Approved", jsonHelper.extractStringNamed("value", statusInGetResponse));
|
||||
|
||||
// Repayment schedule will not be available in the response
|
||||
Assertions.assertFalse(responses.get(2).getBody().contains("repaymentSchedule"));
|
||||
|
||||
// Repayment schedule information will be available in the response based on the query parameter
|
||||
Assertions.assertTrue(responses.get(3).getBody().contains("repaymentSchedule"));
|
||||
}
|
||||
}
|
||||
|
||||
+95
-3
@@ -26,6 +26,7 @@ import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.ws.rs.HttpMethod;
|
||||
import org.apache.fineract.batch.domain.BatchRequest;
|
||||
import org.apache.fineract.batch.domain.BatchResponse;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
@@ -236,14 +237,52 @@ public final class BatchHelper {
|
||||
br.setMethod("POST");
|
||||
br.setReference(reference);
|
||||
|
||||
final String body = "{\"dateFormat\": \"dd MMMM yyyy\", \"locale\": \"en_GB\", \"clientId\": \"$.clientId\"," + "\"productId\": "
|
||||
String body = "{\"dateFormat\": \"dd MMMM yyyy\", \"locale\": \"en_GB\", \"clientId\": \"$.clientId\"," + "\"productId\": "
|
||||
+ productId + ", \"principal\": \"10,000.00\", \"loanTermFrequency\": 10,"
|
||||
+ "\"loanTermFrequencyType\": 2, \"loanType\": \"individual\", \"numberOfRepayments\": 10,"
|
||||
+ "\"repaymentEvery\": 1, \"repaymentFrequencyType\": 2, \"interestRatePerPeriod\": 10,"
|
||||
+ "\"amortizationType\": 1, \"interestType\": 0, \"interestCalculationPeriodType\": 1,"
|
||||
+ "\"transactionProcessingStrategyId\": 1, \"expectedDisbursementDate\": \"10 Jun 2013\",";
|
||||
|
||||
if (clientCollateralId != null) {
|
||||
body = body + "\"collateral\": [{\"clientCollateralId\": \"" + clientCollateralId.toString() + "\", \"quantity\": \"1\"}],";
|
||||
}
|
||||
|
||||
body = body + "\"submittedOnDate\": \"10 Jun 2013\"}";
|
||||
|
||||
br.setBody(body);
|
||||
|
||||
return br;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a {@link org.apache.fineract.batch.command.internal.ApplyLoanCommandStrategy} request with
|
||||
* given clientId and product id.
|
||||
*
|
||||
* @param requestId
|
||||
* the request id
|
||||
* @param clientId
|
||||
* the client id
|
||||
* @param productId
|
||||
* the product id
|
||||
* @return {@link BatchRequest}
|
||||
*/
|
||||
public static BatchRequest applyLoanRequestWithClientId(final Long requestId, final Integer clientId, final Integer productId) {
|
||||
|
||||
final BatchRequest br = new BatchRequest();
|
||||
|
||||
br.setRequestId(requestId);
|
||||
br.setRelativeUrl("loans");
|
||||
br.setMethod("POST");
|
||||
|
||||
String body = String.format("{\"dateFormat\": \"dd MMMM yyyy\", \"locale\": \"en_GB\", \"clientId\": %s, "
|
||||
+ "\"productId\": %s, \"principal\": \"10,000.00\", \"loanTermFrequency\": 10,"
|
||||
+ "\"loanTermFrequencyType\": 2, \"loanType\": \"individual\", \"numberOfRepayments\": 10,"
|
||||
+ "\"repaymentEvery\": 1, \"repaymentFrequencyType\": 2, \"interestRatePerPeriod\": 10,"
|
||||
+ "\"amortizationType\": 1, \"interestType\": 0, \"interestCalculationPeriodType\": 1,"
|
||||
+ "\"transactionProcessingStrategyId\": 1, \"expectedDisbursementDate\": \"10 Jun 2013\","
|
||||
+ "\"collateral\": [{\"clientCollateralId\": \"" + clientCollateralId.toString() + "\", \"quantity\": \"1\"}],"
|
||||
+ "\"submittedOnDate\": \"10 Jun 2013\"}";
|
||||
+ "\"submittedOnDate\": \"10 Jun 2013\"}", clientId, productId);
|
||||
|
||||
br.setBody(body);
|
||||
|
||||
return br;
|
||||
@@ -419,4 +458,57 @@ public final class BatchHelper {
|
||||
final Integer responseRecords = Utils.performServerGet(requestSpec, responseSpec, CLIENT_URL, "totalFilteredRecords");
|
||||
Assertions.assertEquals((long) 0, (long) responseRecords, "No records found with given externalId");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a {@link org.apache.fineract.batch.command.internal.GetTransactionByIdCommandStrategy}
|
||||
* request with given requestId and reference.
|
||||
*
|
||||
* @param requestId
|
||||
* the request id
|
||||
* @param reference
|
||||
* the reference
|
||||
* @return the {@link BatchRequest}
|
||||
*/
|
||||
public static BatchRequest getTransactionByIdRequest(final Long requestId, final Long reference) {
|
||||
|
||||
final BatchRequest br = new BatchRequest();
|
||||
String relativeUrl = "loans/$.loanId/transactions/$.resourceId";
|
||||
|
||||
br.setRequestId(requestId);
|
||||
br.setRelativeUrl(relativeUrl);
|
||||
br.setMethod(HttpMethod.GET);
|
||||
br.setReference(reference);
|
||||
br.setBody("{}");
|
||||
|
||||
return br;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a {@link org.apache.fineract.batch.command.internal.GetLoanByIdCommandStrategy} request with
|
||||
* given requestId and reference.
|
||||
*
|
||||
* @param requestId
|
||||
* the request id
|
||||
* @param reference
|
||||
* the reference
|
||||
* @param queryParameter
|
||||
* the query parameters
|
||||
* @return the {@link BatchRequest}
|
||||
*/
|
||||
public static BatchRequest getLoanByIdRequest(final Long requestId, final Long reference, final String queryParameter) {
|
||||
|
||||
final BatchRequest br = new BatchRequest();
|
||||
String relativeUrl = "loans/$.loanId";
|
||||
if (queryParameter != null) {
|
||||
relativeUrl = relativeUrl + "?" + queryParameter;
|
||||
}
|
||||
|
||||
br.setRequestId(requestId);
|
||||
br.setRelativeUrl(relativeUrl);
|
||||
br.setMethod(HttpMethod.GET);
|
||||
br.setReference(reference);
|
||||
br.setBody("{}");
|
||||
|
||||
return br;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user