FINERACT-1724

Added batch support for the Get Charge by Id call.
Added externalId field to PostLoansLoanIdChargesRequest.
Added submittedOnDate column to m_loan_charge table.
Updated logic to return new submittedOnDate field in GetLoansLoanIdChargesChargeIdResponse.
This commit is contained in:
Arnold Galovics
2022-10-14 17:57:29 +02:00
committed by Arnold Gálovics
parent b33e3ac892
commit 388612b1ae
14 changed files with 410 additions and 13 deletions
+1
View File
@@ -156,6 +156,7 @@ allprojects {
"**/build.gradle.mustache",
"**/pom.mustache",
"**/avro/**/*.java",
"**/org/apache/fineract/client/**/*.java"
])
strictCheck true
}
@@ -91,6 +91,8 @@ public class CommandStrategyProvider {
this.commandStrategies.put(CommandContext.resource("loans\\/\\d+\\/charges").method("POST").build(), "createChargeCommandStrategy");
this.commandStrategies.put(CommandContext.resource("loans\\/\\d+\\/charges").method("GET").build(),
"collectChargesCommandStrategy");
this.commandStrategies.put(CommandContext.resource("loans\\/\\d+\\/charges\\/\\d+").method("GET").build(),
"getChargeByIdCommandStrategy");
this.commandStrategies.put(CommandContext.resource("loans\\/\\d+\\/transactions\\?command=repayment").method("POST").build(),
"createTransactionLoanCommandStrategy");
this.commandStrategies.put(
@@ -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 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.command.CommandStrategyUtils;
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.LoanChargesApiResource;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Component;
/**
* Implements {@link CommandStrategy} to retrieve a charge by id. It passes the contents of the body from the
* BatchRequest to {@link LoanChargesApiResource} and gets back the response. This class will also catch any errors
* raised by {@link LoanChargesApiResource} and map those errors to appropriate status codes in BatchResponse.
*
* @see CommandStrategy
* @see BatchRequest
* @see BatchResponse
*/
@Component
@RequiredArgsConstructor
public class GetChargeByIdCommandStrategy implements CommandStrategy {
private final LoanChargesApiResource loanChargesApiResource;
@Override
public BatchResponse execute(final BatchRequest request, 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();
// Get the loan and charge ids for use in loanChargesApiResource
final List<String> pathParameters = Splitter.on('/').splitToList(relativeUrl);
final Long loanId = Long.parseLong(pathParameters.get(1));
Long chargeId;
if (relativeUrl.indexOf('?') > 0) {
chargeId = Long.parseLong(StringUtils.substringBeforeLast(pathParameters.get(3), "?"));
} else {
chargeId = Long.parseLong(pathParameters.get(3));
}
Map<String, String> queryParameters;
if (relativeUrl.indexOf('?') > 0) {
queryParameters = CommandStrategyUtils.getQueryParameters(relativeUrl);
// Add the query parameters sent in the relative URL to UriInfo
CommandStrategyUtils.addQueryParametersToUriInfo(parameterizedUriInfo, queryParameters);
}
responseBody = loanChargesApiResource.retrieveLoanCharge(loanId, chargeId, parameterizedUriInfo);
response.setStatusCode(HttpStatus.SC_OK);
response.setBody(responseBody);
return response;
}
}
@@ -19,6 +19,7 @@
package org.apache.fineract.portfolio.loanaccount.api;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.LocalDate;
import java.util.Set;
/**
@@ -102,6 +103,8 @@ final class LoanChargesApiResourceSwagger {
public Double amountOrPercentage;
@Schema(example = "false")
public Boolean penalty;
@Schema(example = "27 March 2013")
public LocalDate submittedOnDate;
}
@Schema(description = "GetLoansLoanIdChargesTemplateResponse")
@@ -179,6 +182,8 @@ final class LoanChargesApiResourceSwagger {
public String dateFormat;
@Schema(example = "29 April 2013")
public String dueDate;
@Schema(example = "786444UUUYYH7")
public String externalId;
}
@Schema(description = " PostLoansLoanIdChargesResponse")
@@ -39,6 +39,8 @@ public class LoanChargeData {
private final String name;
private final EnumOptionData chargeTimeType;
private final LocalDate submittedOnDate;
private final LocalDate dueDate;
private final EnumOptionData chargeCalculationType;
@@ -103,10 +105,10 @@ public class LoanChargeData {
public LoanChargeData(final Long id, final Long chargeId, final String name, final CurrencyData currency, final BigDecimal amount,
final BigDecimal amountPaid, final BigDecimal amountWaived, final BigDecimal amountWrittenOff,
final BigDecimal amountOutstanding, final EnumOptionData chargeTimeType, final LocalDate dueDate,
final EnumOptionData chargeCalculationType, final BigDecimal percentage, final BigDecimal amountPercentageAppliedTo,
final boolean penalty, final EnumOptionData chargePaymentMode, final boolean paid, final boolean waived, final Long loanId,
final BigDecimal minCap, final BigDecimal maxCap, final BigDecimal amountOrPercentage,
final BigDecimal amountOutstanding, final EnumOptionData chargeTimeType, final LocalDate submittedOnDate,
final LocalDate dueDate, final EnumOptionData chargeCalculationType, final BigDecimal percentage,
final BigDecimal amountPercentageAppliedTo, final boolean penalty, final EnumOptionData chargePaymentMode, final boolean paid,
final boolean waived, final Long loanId, final BigDecimal minCap, final BigDecimal maxCap, final BigDecimal amountOrPercentage,
Collection<LoanInstallmentChargeData> installmentChargeData, final String externalId) {
this.id = id;
this.chargeId = chargeId;
@@ -118,6 +120,7 @@ public class LoanChargeData {
this.amountWrittenOff = amountWrittenOff;
this.amountOutstanding = amountOutstanding;
this.chargeTimeType = chargeTimeType;
this.submittedOnDate = submittedOnDate;
this.dueDate = dueDate;
this.chargeCalculationType = chargeCalculationType;
this.percentage = percentage;
@@ -162,6 +165,7 @@ public class LoanChargeData {
this.amountWrittenOff = BigDecimal.ZERO;
this.amountOutstanding = amount;
this.chargeTimeType = chargeTimeType;
this.submittedOnDate = null;
this.dueDate = null;
this.chargeCalculationType = chargeCalculationType;
this.percentage = percentage;
@@ -203,6 +207,7 @@ public class LoanChargeData {
this.amountWrittenOff = null;
this.amountOutstanding = amountOutstanding;
this.chargeTimeType = chargeTimeType;
this.submittedOnDate = null;
this.dueDate = dueAsOfDate;
this.chargeCalculationType = null;
this.percentage = null;
@@ -234,6 +239,7 @@ public class LoanChargeData {
this.amountWrittenOff = null;
this.amountOutstanding = null;
this.chargeTimeType = chargeTimeType;
this.submittedOnDate = null;
this.dueDate = dueAsOfDate;
this.chargeCalculationType = null;
this.percentage = null;
@@ -264,6 +270,7 @@ public class LoanChargeData {
this.amountWrittenOff = null;
this.amountOutstanding = null;
this.chargeTimeType = chargeData.chargeTimeType;
this.submittedOnDate = chargeData.submittedOnDate;
this.dueDate = chargeData.dueDate;
this.chargeCalculationType = null;
this.percentage = null;
@@ -294,6 +301,7 @@ public class LoanChargeData {
this.amountWrittenOff = chargeData.amountWrittenOff;
this.amountOutstanding = chargeData.amountOutstanding;
this.chargeTimeType = chargeData.chargeTimeType;
this.submittedOnDate = chargeData.submittedOnDate;
this.dueDate = chargeData.dueDate;
this.chargeCalculationType = chargeData.chargeCalculationType;
this.percentage = chargeData.percentage;
@@ -326,6 +334,7 @@ public class LoanChargeData {
this.amountWrittenOff = null;
this.amountOutstanding = null;
this.chargeTimeType = chargeTimeType;
this.submittedOnDate = null;
this.dueDate = dueAsOfDate;
this.chargeCalculationType = chargeCalculationType;
this.percentage = null;
@@ -356,6 +365,7 @@ public class LoanChargeData {
this.amountWrittenOff = null;
this.amountOutstanding = null;
this.chargeTimeType = null;
this.submittedOnDate = null;
this.dueDate = dueAsOfDate;
this.chargeCalculationType = null;
this.percentage = null;
@@ -42,6 +42,7 @@ import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
@@ -68,6 +69,9 @@ public class LoanCharge extends AbstractPersistableCustom {
@Column(name = "charge_time_enum", nullable = false)
private Integer chargeTime;
@Column(name = "submitted_on_date", nullable = true)
private LocalDate submittedOnDate;
@Column(name = "due_for_collection_as_of_date")
private LocalDate dueDate;
@@ -229,6 +233,7 @@ public class LoanCharge extends AbstractPersistableCustom {
final ChargePaymentMode chargePaymentMode, final Integer numberOfRepayments, final BigDecimal loanCharge) {
this.loan = loan;
this.charge = chargeDefinition;
this.submittedOnDate = DateUtils.getBusinessLocalDate();
this.penaltyCharge = chargeDefinition.isPenalty();
this.minCap = chargeDefinition.getMinCap();
this.maxCap = chargeDefinition.getMaxCap();
@@ -597,6 +602,10 @@ public class LoanCharge extends AbstractPersistableCustom {
return this.dueDate;
}
public LocalDate getSubmittedOnDate() {
return submittedOnDate;
}
private boolean determineIfFullyPaid() {
if (this.amount == null) {
return true;
@@ -59,8 +59,8 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
private static final class LoanChargeMapper implements RowMapper<LoanChargeData> {
public String schema() {
return "lc.id as id, lc.external_id as externalId, c.id as chargeId, c.name as name, " + "lc.amount as amountDue, "
+ "lc.amount_paid_derived as amountPaid, " + "lc.amount_waived_derived as amountWaived, "
return "lc.id as id, lc.external_id as externalId, c.id as chargeId, c.name as name, lc.submitted_on_date as submittedOnDate, "
+ "lc.amount as amountDue, " + "lc.amount_paid_derived as amountPaid, " + "lc.amount_waived_derived as amountWaived, "
+ "lc.amount_writtenoff_derived as amountWrittenOff, " + "lc.amount_outstanding_derived as amountOutstanding, "
+ "lc.calculation_percentage as percentageOf, lc.calculation_on_amount as amountPercentageAppliedTo, "
+ "lc.charge_time_enum as chargeTime, " + "lc.is_penalty as penalty, "
@@ -116,6 +116,7 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
final BigDecimal maxCap = rs.getBigDecimal("maxCap");
final BigDecimal amountOrPercentage = rs.getBigDecimal("amountOrPercentage");
final LocalDate disbursementDate = JdbcSupport.getLocalDate(rs, "disbursementDate");
final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate");
if (disbursementDate != null) {
dueAsOfDate = disbursementDate;
@@ -123,8 +124,8 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
final String externalId = rs.getString("externalId");
return new LoanChargeData(id, chargeId, name, currency, amount, amountPaid, amountWaived, amountWrittenOff, amountOutstanding,
chargeTimeType, dueAsOfDate, chargeCalculationType, percentageOf, amountPercentageAppliedTo, penalty, paymentMode, paid,
waived, null, minCap, maxCap, amountOrPercentage, null, externalId);
chargeTimeType, submittedOnDate, dueAsOfDate, chargeCalculationType, percentageOf, amountPercentageAppliedTo, penalty,
paymentMode, paid, waived, null, minCap, maxCap, amountOrPercentage, null, externalId);
}
}
@@ -526,7 +526,8 @@ public final class LoanProductDataValidator {
baseDataValidator.reset().parameter(LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName)
.value(fixedPrincipalPercentagePerInstallment).notLessThanMin(BigDecimal.ONE).notGreaterThanMax(BigDecimal.valueOf(100));
if (!amortizationType.equals(AmortizationMethod.EQUAL_PRINCIPAL.getValue()) && fixedPrincipalPercentagePerInstallment != null) {
if (amortizationType != null && !amortizationType.equals(AmortizationMethod.EQUAL_PRINCIPAL.getValue())
&& fixedPrincipalPercentagePerInstallment != null) {
baseDataValidator.reset().parameter(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName).failWithCode(
"not.supported.principal.fixing.not.allowed.with.equal.installments",
"Principal fixing cannot be done with equal installment amortization");
@@ -74,4 +74,5 @@
<include file="parts/0052_loan_transaction_chargeback.xml" relativeToChangelogFile="true"/>
<include file="parts/0053_add_external_events_purge_job.xml" relativeToChangelogFile="true"/>
<include file="parts/0054_additional_fields_loan_repayment_schedule.xml" relativeToChangelogFile="true"/>
<include file="parts/0055_add_submitted_on_date_to_loan_charge.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<changeSet author="fineract" id="1">
<addColumn tableName="m_loan_charge">
<column name="submitted_on_date" type="date">
<constraints nullable="true"/>
</column>
</addColumn>
</changeSet>
</databaseChangeLog>
@@ -36,6 +36,7 @@ import org.apache.fineract.batch.command.internal.CreateClientCommandStrategy;
import org.apache.fineract.batch.command.internal.CreateLoanRescheduleRequestCommandStrategy;
import org.apache.fineract.batch.command.internal.CreateTransactionLoanCommandStrategy;
import org.apache.fineract.batch.command.internal.DisburseLoanCommandStrategy;
import org.apache.fineract.batch.command.internal.GetChargeByIdCommandStrategy;
import org.apache.fineract.batch.command.internal.GetDatatableEntryByAppTableIdCommandStrategy;
import org.apache.fineract.batch.command.internal.GetLoanByIdCommandStrategy;
import org.apache.fineract.batch.command.internal.GetTransactionByIdCommandStrategy;
@@ -69,6 +70,8 @@ public class CommandStrategyProviderTest {
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/charges/123", HttpMethod.GET, "getChargeByIdCommandStrategy",
mock(GetChargeByIdCommandStrategy.class)),
Arguments.of("loans/123/transactions?command=repayment", HttpMethod.POST, "createTransactionLoanCommandStrategy",
mock(CreateTransactionLoanCommandStrategy.class)),
Arguments.of("loans/123/transactions?command=creditBalanceRefund", HttpMethod.POST, "createTransactionLoanCommandStrategy",
@@ -130,7 +133,8 @@ public class CommandStrategyProviderTest {
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),
Arguments.of("datatables/test_dt_table", HttpMethod.GET), Arguments.of("datatables", HttpMethod.GET));
Arguments.of("datatables/test_dt_table", HttpMethod.GET), Arguments.of("datatables", HttpMethod.GET),
Arguments.of("loans//charges/123", HttpMethod.GET), Arguments.of("loans/123/charges/", HttpMethod.GET));
}
@@ -0,0 +1,149 @@
/**
* 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.LoanChargesApiResource;
import org.apache.http.HttpStatus;
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;
/**
* The {@link GetChargeByIdCommandStrategy} test class.
*/
public class GetChargeByIdCommandStrategyTest {
/**
* Query parameter provider.
*
* @return the test data stream
*/
private static Stream<Arguments> provideQueryParameters() {
return Stream.of(Arguments.of(null, 0), Arguments.of("fields=name,amountOrPercentage", 1));
}
/**
* Test {@link GetChargeByIdCommandStrategy#execute} happy path scenario.
*/
@ParameterizedTest
@MethodSource("provideQueryParameters")
public void testExecuteSuccessScenario(final String queryParameter, final int numberOfQueryParams) {
final TestContext testContext = new TestContext();
final Long loanId = Long.valueOf(RandomStringUtils.randomNumeric(4));
final Long chargeId = Long.valueOf(RandomStringUtils.randomNumeric(4));
final BatchRequest request = getBatchRequest(loanId, chargeId, queryParameter);
final String responseBody = "someResponseBody";
given(testContext.loanChargesApiResource.retrieveLoanCharge(eq(loanId), eq(chargeId), any(UriInfo.class))).willReturn(responseBody);
final BatchResponse response = testContext.subjectToTest.execute(request, testContext.uriInfo);
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.loanChargesApiResource).retrieveLoanCharge(eq(loanId), eq(chargeId), testContext.uriInfoCaptor.capture());
MutableUriInfo mutableUriInfo = testContext.uriInfoCaptor.getValue();
assertThat(mutableUriInfo.getAdditionalQueryParameters()).hasSize(numberOfQueryParams);
}
/**
* Creates and returns a request with the given loan id and charge id.
*
* @param loanId
* the loan id
* @param chargeId
* the charge id
* @param queryParameter
* the query parameter
* @return BatchRequest
*/
private BatchRequest getBatchRequest(final Long loanId, final Long chargeId, final String queryParameter) {
final BatchRequest br = new BatchRequest();
String relativeUrl = "loans/" + loanId + "/charges/" + chargeId;
if (queryParameter != null) {
relativeUrl = relativeUrl + "?" + queryParameter;
}
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 {
/**
* The subject to test
*/
private final GetChargeByIdCommandStrategy subjectToTest;
/**
* The mock uri info
*/
@Mock
private UriInfo uriInfo;
/**
* The mock {@link LoanChargesApiResource} object.
*/
@Mock
private LoanChargesApiResource loanChargesApiResource;
/**
* The uri info captor
*/
@Captor
private ArgumentCaptor<MutableUriInfo> uriInfoCaptor;
/**
* Test Context constructor
*/
TestContext() {
MockitoAnnotations.openMocks(this);
subjectToTest = new GetChargeByIdCommandStrategy(loanChargesApiResource);
}
}
}
@@ -34,6 +34,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.fineract.batch.command.internal.AdjustTransactionCommandStrategy;
import org.apache.fineract.batch.command.internal.CreateTransactionLoanCommandStrategy;
import org.apache.fineract.batch.domain.BatchRequest;
@@ -43,6 +44,7 @@ import org.apache.fineract.integrationtests.common.BatchHelper;
import org.apache.fineract.integrationtests.common.ClientHelper;
import org.apache.fineract.integrationtests.common.CollateralManagementHelper;
import org.apache.fineract.integrationtests.common.Utils;
import org.apache.fineract.integrationtests.common.charges.ChargesHelper;
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
import org.apache.fineract.integrationtests.common.savings.SavingsProductHelper;
@@ -377,6 +379,69 @@ public class BatchApiTest {
Assertions.assertEquals(HttpStatus.SC_OK, (long) response.get(3).getStatusCode(), "Verify Status Code 200 for Create Loan Charge");
}
/**
* Tests that a new charge was added to a newly created loan and charges are Collected properly 200(OK) status was
* returned for successful responses. It first creates a new client and apply a loan, then creates a new charge for
* the create loan and then fetches all the applied charges
*
* @see org.apache.fineract.batch.command.internal.CollectChargesCommandStrategy
* @see org.apache.fineract.batch.command.internal.CreateChargeCommandStrategy
*/
@Test
public void shouldReturnOkStatusForCreateAndGetChargeByIdCommand() {
final String loanProductJSON = new LoanProductTestBuilder() //
.withPrincipal("1000.00") //
.withNumberOfRepayments("24") //
.withRepaymentAfterEvery("1") //
.withRepaymentTypeAsMonth() //
.withinterestRatePerPeriod("2") //
.withInterestRateFrequencyTypeAsMonths() //
.withAmortizationTypeAsEqualPrincipalPayment() //
.withInterestTypeAsDecliningBalance() //
.currencyDetails("0", "100").build(null);
final Long applyLoanRequestId = Long.valueOf(RandomStringUtils.randomNumeric(4));
final Long approveLoanRequestId = applyLoanRequestId + 1;
final Long disburseLoanRequestId = approveLoanRequestId + 1;
final Long createChargeRequestId = disburseLoanRequestId + 1;
final Long getChargeByIdRequestId = createChargeRequestId + 1;
// 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 charge object and get id
final Integer chargeId = ChargesHelper.createCharges(this.requestSpec, this.responseSpec,
ChargesHelper.getLoanSpecifiedDueDateJSON());
final BatchRequest applyLoanRequest = BatchHelper.applyLoanRequestWithClientId(applyLoanRequestId, clientId, productId);
final BatchRequest approveLoanRequest = BatchHelper.approveLoanRequest(approveLoanRequestId, applyLoanRequestId);
final BatchRequest disburseLoanRequest = BatchHelper.disburseLoanRequest(disburseLoanRequestId, approveLoanRequestId);
final BatchRequest createChargeRequest = BatchHelper.createChargeRequest(createChargeRequestId, disburseLoanRequestId, chargeId);
final BatchRequest getChargeByIdRequest = BatchHelper.getChargeByIdCommandStrategy(getChargeByIdRequestId, createChargeRequestId);
// Create batch requests list
final List<BatchRequest> batchRequests = Arrays.asList(applyLoanRequest, approveLoanRequest, disburseLoanRequest,
createChargeRequest, getChargeByIdRequest);
// Create batch responses list
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 Create Charge");
Assertions.assertEquals(HttpStatus.SC_OK, responses.get(4).getStatusCode(), "Verify Status Code 200 for Get Charge By Id");
}
/**
* Tests that batch repayment for loans is happening properly. Collected properly 200(OK) status was returned for
* successful responses. It first creates a new loan and then makes two repayments for it and then verifies that
@@ -349,10 +349,14 @@ public final class BatchHelper {
* given requestId and reference
*
* @param requestId
* the batch request id.
* @param reference
* the reference id.
* @param chargeId
* the charge id used for getting charge type.
* @return BatchRequest
*/
public static BatchRequest createChargeRequest(final Long requestId, final Long reference) {
public static BatchRequest createChargeRequest(final Long requestId, final Long reference, final Integer chargeId) {
final BatchRequest br = new BatchRequest();
br.setRequestId(requestId);
@@ -360,8 +364,12 @@ public final class BatchHelper {
br.setMethod("POST");
br.setReference(reference);
final String body = "{\"chargeId\": \"2\", \"locale\": \"en\", \"amount\": \"100\", "
+ "\"dateFormat\": \"dd MMMM yyyy\", \"dueDate\": \"29 April 2013\"}";
final String dateFormat = "dd MMMM yyyy";
final String dateString = LocalDate.now(Utils.getZoneIdOfTenant()).format(DateTimeFormatter.ofPattern(dateFormat));
final String body = String.format(
"{\"chargeId\": \"%d\", \"locale\": \"en\", \"amount\": \"11.15\", " + "\"dateFormat\": \"%s\", \"dueDate\": \"%s\"}",
chargeId, dateFormat, dateString);
br.setBody(body);
return br;
@@ -388,6 +396,30 @@ public final class BatchHelper {
return br;
}
/**
* Creates and returns a {@link org.apache.fineract.batch.command.internal.GetChargeByIdCommandStrategy} request
* with given requestId and reference.
*
* @param requestId
* the request id
* @param reference
* the reference
* @return the {@link BatchRequest}
*/
public static BatchRequest getChargeByIdCommandStrategy(final Long requestId, final Long reference) {
final BatchRequest br = new BatchRequest();
String relativeUrl = "loans/$.loanId/charges/$.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.ActivateClientCommandStrategy} Request
* with given requestId and reference.