FINERACT-2020:Added currency field to LoanAccountSummaryData, also added integration test and swagger documentation
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/data/LoanAccountSummaryData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/data/LoanAccountSummaryData.java
index 4ef5400..aa52620 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/data/LoanAccountSummaryData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/data/LoanAccountSummaryData.java
@@ -22,6 +22,7 @@
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.portfolio.loanaccount.data.LoanApplicationTimelineData;
import org.apache.fineract.portfolio.loanaccount.data.LoanStatusEnumData;
@@ -40,6 +41,7 @@
private final String productName;
private final String shortProductName;
private final LoanStatusEnumData status;
+ private final CurrencyData currency;
private final EnumOptionData loanType;
private final Integer loanCycle;
private final LoanApplicationTimelineData timeline;
@@ -50,8 +52,8 @@
public LoanAccountSummaryData(final Long id, final String accountNo, final String externalId, final Long productId,
final String loanProductName, final String shortLoanProductName, final LoanStatusEnumData loanStatus,
- final EnumOptionData loanType, final Integer loanCycle, final LoanApplicationTimelineData timeline, final Boolean inArrears,
- final BigDecimal originalLoan, final BigDecimal loanBalance, final BigDecimal amountPaid) {
+ final CurrencyData currency, final EnumOptionData loanType, final Integer loanCycle, final LoanApplicationTimelineData timeline,
+ final Boolean inArrears, final BigDecimal originalLoan, final BigDecimal loanBalance, final BigDecimal amountPaid) {
this.id = id;
this.accountNo = accountNo;
this.parentAccountNumber = null;
@@ -60,6 +62,7 @@
this.productName = loanProductName;
this.shortProductName = shortLoanProductName;
this.status = loanStatus;
+ this.currency = currency;
this.loanType = loanType;
this.loanCycle = loanCycle;
this.timeline = timeline;
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/service/AccountDetailsReadPlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/service/AccountDetailsReadPlatformServiceJpaRepositoryImpl.java
index 2f5e161..7c1f508 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/service/AccountDetailsReadPlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/service/AccountDetailsReadPlatformServiceJpaRepositoryImpl.java
@@ -452,6 +452,11 @@
.append(" l.loan_product_counter as loanCycle,")
+ .append("l.currency_code as currencyCode, l.currency_digits as currencyDigits, l.currency_multiplesof as inMultiplesOf,")
+
+ .append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode,")
+ .append("curr.display_symbol as currencyDisplaySymbol,")
+
.append(" l.submittedon_date as submittedOnDate,")
.append(" sbu.username as submittedByUsername, sbu.firstname as submittedByFirstname, sbu.lastname as submittedByLastname,")
@@ -474,6 +479,7 @@
.append(" l.charged_off_on_date as chargedOffOnDate, cobu.username as chargedOffByUsername, ")
.append(" cobu.firstname as chargedOffByFirstname, cobu.lastname as chargedOffByLastname ").append(" from m_loan l ")
.append("LEFT JOIN m_product_loan AS lp ON lp.id = l.product_id")
+ .append(" left join m_currency curr on curr.code = l.currency_code")
.append(" left join m_appuser sbu on sbu.id = l.created_by")
.append(" left join m_appuser rbu on rbu.id = l.rejectedon_userid")
.append(" left join m_appuser wbu on wbu.id = l.withdrawnon_userid")
@@ -503,6 +509,15 @@
final EnumOptionData loanType = AccountEnumerations.loanType(loanTypeId);
final Integer loanCycle = JdbcSupport.getInteger(rs, "loanCycle");
+ final String currencyCode = rs.getString("currencyCode");
+ final String currencyName = rs.getString("currencyName");
+ final String currencyNameCode = rs.getString("currencyNameCode");
+ final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
+ final Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
+ final Integer inMultiplesOf = JdbcSupport.getInteger(rs, "inMultiplesOf");
+ final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf, currencyDisplaySymbol,
+ currencyNameCode);
+
final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate");
final String submittedByUsername = rs.getString("submittedByUsername");
final String submittedByFirstname = rs.getString("submittedByFirstname");
@@ -561,7 +576,8 @@
chargedOffOnDate, chargedOffByUsername, chargedOffByFirstname, chargedOffByLastname);
return new LoanAccountSummaryData(id, accountNo, parentAccountNumber, externalId, productId, loanProductName,
- shortLoanProductName, loanStatus, loanType, loanCycle, timeline, inArrears, originalLoan, loanBalance, amountPaid);
+ shortLoanProductName, loanStatus, currency, loanType, loanCycle, timeline, inArrears, originalLoan, loanBalance,
+ amountPaid);
}
}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResourceSwagger.java
index bf5e6dd..b93d661 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResourceSwagger.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResourceSwagger.java
@@ -470,6 +470,24 @@
private GetClientsLoanAccounts() {}
+ static final class GetClientsLoansAccountsCurrency {
+
+ private GetClientsLoansAccountsCurrency() {}
+
+ @Schema(example = "USD")
+ public String code;
+ @Schema(example = "US Dollar")
+ public String name;
+ @Schema(example = "2")
+ public Integer decimalPlaces;
+ @Schema(example = "$")
+ public String displaySymbol;
+ @Schema(example = "currency.USD")
+ public String nameCode;
+ @Schema(example = "US Dollar ($)")
+ public String displayLabel;
+ }
+
static final class GetClientsLoanAccountsStatus {
private GetClientsLoanAccountsStatus() {}
@@ -520,6 +538,7 @@
public Long productId;
@Schema(example = "TestOne")
public String productName;
+ public GetClientsLoansAccountsCurrency currency;
public GetClientsLoanAccountsStatus status;
public GetClientsLoanAccountsType loanType;
@Schema(example = "1")
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountsContainsCurrencyFieldTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountsContainsCurrencyFieldTest.java
new file mode 100644
index 0000000..4ee2cc9
--- /dev/null
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountsContainsCurrencyFieldTest.java
@@ -0,0 +1,151 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.integrationtests;
+
+import io.restassured.builder.RequestSpecBuilder;
+import io.restassured.builder.ResponseSpecBuilder;
+import io.restassured.http.ContentType;
+import io.restassured.specification.RequestSpecification;
+import io.restassured.specification.ResponseSpecification;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Set;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.client.models.GetClientsClientIdAccountsResponse;
+import org.apache.fineract.client.models.GetClientsLoanAccounts;
+import org.apache.fineract.client.models.PostClientsResponse;
+import org.apache.fineract.integrationtests.common.ClientHelper;
+import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
+import org.apache.fineract.integrationtests.common.Utils;
+import org.apache.fineract.integrationtests.common.accounting.Account;
+import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
+import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
+import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Slf4j
+public class LoanAccountsContainsCurrencyFieldTest {
+
+ private ResponseSpecification responseSpec;
+ private RequestSpecification requestSpec;
+ private LoanTransactionHelper loanTransactionHelper;
+ private static final String principalAmount = "1200.00";
+ private static final String NONE = "1";
+ private static final Logger LOG = LoggerFactory.getLogger(LoanAccountsContainsCurrencyFieldTest.class);
+
+ @BeforeEach
+ public void setup() {
+ Utils.initializeRESTAssured();
+ requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
+ requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
+ responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
+
+ loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
+ }
+
+ @Test
+ public void testGetClientLoanAccountsUsingExternalIdContainsCurrency() {
+
+ // Get today's date
+ LocalDate today = LocalDate.now(ZoneId.systemDefault());
+
+ // Define a custom date formatter
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MMMM yyyy");
+
+ // Format today's date using the custom formatter
+ String formattedDate = today.format(formatter);
+
+ // given
+ GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec,
+ GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, true);
+ final String jsonPayload = ClientHelper.getBasicClientAsJSON(ClientHelper.DEFAULT_OFFICE_ID, ClientHelper.LEGALFORM_ID_PERSON,
+ null);
+ // when
+ final PostClientsResponse clientResponse = ClientHelper.addClientAsPerson(requestSpec, responseSpec, jsonPayload);
+ final String clientExternalId = clientResponse.getResourceExternalId();
+ final long clientId = clientResponse.getClientId();
+
+ GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec,
+ GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, false);
+
+ Integer loanProductId = createLoanProduct(false, NONE);
+
+ // Create Loan Account
+ final Integer loanId = createLoanAccount(loanTransactionHelper, String.valueOf(clientId), String.valueOf(loanProductId),
+ formattedDate);
+
+ GetClientsClientIdAccountsResponse clientAccountsResponse = ClientHelper.getClientAccounts(requestSpec, responseSpec,
+ clientExternalId);
+
+ if (clientAccountsResponse.getLoanAccounts() == null) {
+ // Handle the case where getClientAccounts returned null
+ throw new IllegalStateException("getClientAccounts returned null");
+ }
+
+ final Set<GetClientsLoanAccounts> loanAccounts = clientAccountsResponse.getLoanAccounts();
+
+ // Assert if loanAccounts contains a loan account with "currency" field
+ boolean containsCurrency = false;
+ if (loanAccounts != null) {
+ containsCurrency = loanAccounts.stream().anyMatch(account -> account.getCurrency() != null);
+ }
+
+ // Perform assertion
+ assert containsCurrency;
+
+ }
+
+ private Integer createLoanAccount(final LoanTransactionHelper loanTransactionHelper, final String clientId, final String loanProductId,
+ final String operationDate) {
+ final String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal(principalAmount).withLoanTermFrequency("1")
+ .withLoanTermFrequencyAsMonths().withNumberOfRepayments("1").withRepaymentEveryAfter("1")
+ .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance()
+ .withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod()
+ .withExpectedDisbursementDate("03 September 2022").withSubmittedOnDate("01 September 2022").withLoanType("individual")
+ .build(clientId, loanProductId, null);
+ final Integer loanId = loanTransactionHelper.getLoanId(loanApplicationJSON);
+ loanTransactionHelper.approveLoan(operationDate, principalAmount, loanId, null);
+ return loanId;
+ }
+
+ private Integer createLoanProduct(final boolean multiDisburseLoan, final String accountingRule, final Account... accounts) {
+ LOG.info("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
+ LoanProductTestBuilder builder = new LoanProductTestBuilder() //
+ .withPrincipal("12,000.00") //
+ .withNumberOfRepayments("4") //
+ .withRepaymentAfterEvery("1") //
+ .withRepaymentTypeAsMonth() //
+ .withinterestRatePerPeriod("1") //
+ .withInterestRateFrequencyTypeAsMonths() //
+ .withAmortizationTypeAsEqualInstallments() //
+ .withInterestTypeAsDecliningBalance() //
+ .withTranches(multiDisburseLoan) //
+ .withAccounting(accountingRule, accounts);
+ if (multiDisburseLoan) {
+ builder = builder.withInterestCalculationPeriodTypeAsRepaymentPeriod(true);
+ }
+ final String loanProductJSON = builder.build(null);
+ return loanTransactionHelper.getLoanProductId(loanProductJSON);
+ }
+
+}