This is an automated email from the ASF dual-hosted git repository.
arnold pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new 388612b1a 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.
388612b1a is described below
commit 388612b1ae68bc3ea69678cf352029372fe10faf
Author: Arnold Galovics <[email protected]>
AuthorDate: Fri Oct 14 16:57:26 2022 +0200
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.
---
build.gradle | 1 +
.../batch/command/CommandStrategyProvider.java | 2 +
.../internal/GetChargeByIdCommandStrategy.java | 87 ++++++++++++
.../api/LoanChargesApiResourceSwagger.java | 5 +
.../portfolio/loanaccount/data/LoanChargeData.java | 18 ++-
.../portfolio/loanaccount/domain/LoanCharge.java | 9 ++
.../service/LoanChargeReadPlatformServiceImpl.java | 9 +-
.../serialization/LoanProductDataValidator.java | 3 +-
.../db/changelog/tenant/changelog-tenant.xml | 1 +
.../0055_add_submitted_on_date_to_loan_charge.xml | 30 +++++
.../batch/command/CommandStrategyProviderTest.java | 6 +-
.../internal/GetChargeByIdCommandStrategyTest.java | 149 +++++++++++++++++++++
.../fineract/integrationtests/BatchApiTest.java | 65 +++++++++
.../integrationtests/common/BatchHelper.java | 38 +++++-
14 files changed, 410 insertions(+), 13 deletions(-)
diff --git a/build.gradle b/build.gradle
index 87272d239..af38e01e2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -156,6 +156,7 @@ allprojects {
"**/build.gradle.mustache",
"**/pom.mustache",
"**/avro/**/*.java",
+ "**/org/apache/fineract/client/**/*.java"
])
strictCheck true
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/batch/command/CommandStrategyProvider.java
b/fineract-provider/src/main/java/org/apache/fineract/batch/command/CommandStrategyProvider.java
index 581681ac3..6005a4a9e 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/batch/command/CommandStrategyProvider.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/batch/command/CommandStrategyProvider.java
@@ -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(
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetChargeByIdCommandStrategy.java
b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetChargeByIdCommandStrategy.java
new file mode 100644
index 000000000..2df109b1d
--- /dev/null
+++
b/fineract-provider/src/main/java/org/apache/fineract/batch/command/internal/GetChargeByIdCommandStrategy.java
@@ -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;
+ }
+}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanChargesApiResourceSwagger.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanChargesApiResourceSwagger.java
index 32853c09b..5f97c02a5 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanChargesApiResourceSwagger.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanChargesApiResourceSwagger.java
@@ -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")
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanChargeData.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanChargeData.java
index 68cd919b6..b22825ad1 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanChargeData.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanChargeData.java
@@ -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;
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
index 09079b4ca..302a2b461 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanCharge.java
@@ -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;
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java
index 3c5a7f12c..f9300bcc2 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeReadPlatformServiceImpl.java
@@ -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);
}
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
index 1a83d5120..cb89efb54 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java
@@ -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");
diff --git
a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
index c7e64d63a..1d9f51d22 100644
---
a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
+++
b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
@@ -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>
diff --git
a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0055_add_submitted_on_date_to_loan_charge.xml
b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0055_add_submitted_on_date_to_loan_charge.xml
new file mode 100644
index 000000000..a27aff8e9
--- /dev/null
+++
b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0055_add_submitted_on_date_to_loan_charge.xml
@@ -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>
diff --git
a/fineract-provider/src/test/java/org/apache/fineract/batch/command/CommandStrategyProviderTest.java
b/fineract-provider/src/test/java/org/apache/fineract/batch/command/CommandStrategyProviderTest.java
index d8ae731d4..1fa216a46 100644
---
a/fineract-provider/src/test/java/org/apache/fineract/batch/command/CommandStrategyProviderTest.java
+++
b/fineract-provider/src/test/java/org/apache/fineract/batch/command/CommandStrategyProviderTest.java
@@ -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));
}
diff --git
a/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetChargeByIdCommandStrategyTest.java
b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetChargeByIdCommandStrategyTest.java
new file mode 100644
index 000000000..3e81a1dd6
--- /dev/null
+++
b/fineract-provider/src/test/java/org/apache/fineract/batch/command/internal/GetChargeByIdCommandStrategyTest.java
@@ -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);
+ }
+ }
+}
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchApiTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchApiTest.java
index 1d1ca330d..c29d6371f 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchApiTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BatchApiTest.java
@@ -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
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java
index 93693c882..925764c67 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/BatchHelper.java
@@ -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.