From cf65d81cccd447c0c990f14bd91a73af9a68d78b Mon Sep 17 00:00:00 2001 From: Udo Bassey Date: Thu, 28 Mar 2024 16:41:40 +0100 Subject: [PATCH] FINERACT-2020:Added currency field to LoanAccountSummaryData, also added integration test and swagger documentation --- .../data/LoanAccountSummaryData.java | 7 +- ...sReadPlatformServiceJpaRepositoryImpl.java | 18 ++- .../client/api/ClientsApiResourceSwagger.java | 19 +++ ...LoanAccountsContainsCurrencyFieldTest.java | 151 ++++++++++++++++++ 4 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAccountsContainsCurrencyFieldTest.java 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 4ef5400f8..aa5262072 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 java.math.BigDecimal; 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 @@ public class LoanAccountSummaryData { 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 class LoanAccountSummaryData { 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 @@ public class LoanAccountSummaryData { 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 2f5e1619b..7c1f50873 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 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou .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 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou .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 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou 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 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou 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 bf5e6ddb3..b93d6612c 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 @@ final class ClientsApiResourceSwagger { 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 @@ final class ClientsApiResourceSwagger { 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 000000000..4ee2cc95e --- /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 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); + } + +}