From be935cd55b9f57c9e98f31fa876c64c8163892e7 Mon Sep 17 00:00:00 2001 From: taskain7 Date: Thu, 13 Jul 2023 12:31:37 +0200 Subject: [PATCH] [FINERACT-1760] Loan product external id --- .../infrastructure/core/api/JsonCommand.java | 11 ++ .../loanproduct/domain/LoanProduct.java | 14 ++- .../api/LoanProductsApiResource.java | 103 ++++++++++++++---- .../api/LoanProductsApiResourceSwagger.java | 2 + .../domain/LoanProductRepository.java | 3 + .../LoanProductNotFoundException.java | 5 + .../LoanProductReadPlatformService.java | 4 + .../LoanProductReadPlatformServiceImpl.java | 26 ++--- .../LoanProductExternalIdTest.java | 76 +++++++++++++ .../common/loans/LoanProductHelper.java | 11 ++ .../common/loans/LoanProductTestBuilder.java | 7 ++ 11 files changed, 222 insertions(+), 40 deletions(-) create mode 100644 integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductExternalIdTest.java diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/JsonCommand.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/JsonCommand.java index 49ebc937d..32175c5f7 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/JsonCommand.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/JsonCommand.java @@ -35,6 +35,7 @@ import java.util.Map; import java.util.Set; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.security.domain.BasicPasswordEncodablePlatformUser; import org.apache.fineract.infrastructure.security.domain.PlatformUser; @@ -643,6 +644,16 @@ public final class JsonCommand { return isChanged; } + public boolean isChangeInExternalIdParameterNamed(final String parameterName, final ExternalId externalId) { + boolean isChanged = false; + if (parameterExists(parameterName)) { + final String workingValue = stringValueOfParameterNamed(parameterName); + String existingValue = externalId.getValue(); + isChanged = differenceExists(existingValue, workingValue); + } + return isChanged; + } + public String passwordValueOfParameterNamed(final String parameterName, final PlatformPasswordEncoder platformPasswordEncoder, final Long saltValue) { final String passwordPlainText = stringValueOfParameterNamed(parameterName); diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java index 9ec2258d7..5218cba42 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java @@ -48,6 +48,8 @@ import org.apache.commons.lang3.StringUtils; import org.apache.fineract.accounting.common.AccountingRuleType; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; +import org.apache.fineract.infrastructure.core.domain.ExternalId; +import org.apache.fineract.infrastructure.core.service.ExternalIdFactory; import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.organisation.monetary.domain.Money; import org.apache.fineract.portfolio.charge.domain.Charge; @@ -130,7 +132,7 @@ public class LoanProduct extends AbstractPersistableCustom { private LocalDate closeDate; @Column(name = "external_id", length = 100, unique = true) - private String externalId; + private ExternalId externalId; @OneToMany(cascade = CascadeType.ALL, mappedBy = "loanProduct", orphanRemoval = true, fetch = FetchType.EAGER) private Set borrowerCycleVariations = new HashSet<>(); @@ -290,7 +292,7 @@ public class LoanProduct extends AbstractPersistableCustom { final LocalDate startDate = command.localDateValueOfParameterNamed("startDate"); final LocalDate closeDate = command.localDateValueOfParameterNamed("closeDate"); - final String externalId = command.stringValueOfParameterNamedAllowingNull("externalId"); + final ExternalId externalId = ExternalIdFactory.produce(command.stringValueOfParameterNamedAllowingNull("externalId")); final boolean useBorrowerCycle = command .booleanPrimitiveValueOfParameterNamed(LoanProductConstants.USE_BORROWER_CYCLE_PARAMETER_NAME); @@ -593,7 +595,7 @@ public class LoanProduct extends AbstractPersistableCustom { final Integer graceOnPrincipalPayment, final Integer recurringMoratoriumOnPrincipalPeriods, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance, final List charges, final AccountingRuleType accountingRuleType, - final boolean includeInBorrowerCycle, final LocalDate startDate, final LocalDate closeDate, final String externalId, + final boolean includeInBorrowerCycle, final LocalDate startDate, final LocalDate closeDate, final ExternalId externalId, final boolean useBorrowerCycle, final Set loanProductBorrowerCycleVariations, final boolean multiDisburseLoan, final Integer maxTrancheCount, final BigDecimal outstandingLoanBalance, final Integer graceOnArrearsAgeing, final Integer overdueDaysForNPA, final DaysInMonthType daysInMonthType, @@ -964,8 +966,8 @@ public class LoanProduct extends AbstractPersistableCustom { } final String externalIdTypeParamName = "externalId"; - if (command.isChangeInStringParameterNamed(externalIdTypeParamName, this.externalId)) { - final String newValue = command.stringValueOfParameterNamed(externalIdTypeParamName); + if (command.isChangeInExternalIdParameterNamed(externalIdTypeParamName, this.externalId)) { + final ExternalId newValue = ExternalIdFactory.produce(command.stringValueOfParameterNamed(externalIdTypeParamName)); actualChanges.put(accountingTypeParamName, newValue); this.externalId = newValue; } @@ -1315,7 +1317,7 @@ public class LoanProduct extends AbstractPersistableCustom { return this.name; } - public String getExternalId() { + public ExternalId getExternalId() { return this.externalId; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java index c834a7aca..910b8069e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java @@ -43,6 +43,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import lombok.RequiredArgsConstructor; import org.apache.fineract.accounting.common.AccountingDropdownReadPlatformService; @@ -58,8 +59,10 @@ import org.apache.fineract.infrastructure.core.api.ApiParameterHelper; import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer; +import org.apache.fineract.infrastructure.core.service.ExternalIdFactory; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.monetary.service.CurrencyReadPlatformService; @@ -76,6 +79,7 @@ import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants; import org.apache.fineract.portfolio.loanproduct.LoanProductConstants; import org.apache.fineract.portfolio.loanproduct.data.LoanProductData; import org.apache.fineract.portfolio.loanproduct.data.TransactionProcessingStrategyData; +import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException; import org.apache.fineract.portfolio.loanproduct.productmix.data.ProductMixData; import org.apache.fineract.portfolio.loanproduct.productmix.service.ProductMixReadPlatformService; import org.apache.fineract.portfolio.loanproduct.service.LoanDropdownReadPlatformService; @@ -230,6 +234,86 @@ public class LoanProductsApiResource { this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); + return getLoanProductDetails(productId, uriInfo); + } + + @PUT + @Path("{productId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Update a Loan Product", description = "Updates a Loan Product") + @RequestBody(required = true, content = @Content(schema = @Schema(implementation = LoanProductsApiResourceSwagger.PutLoanProductsProductIdRequest.class))) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = LoanProductsApiResourceSwagger.PutLoanProductsProductIdResponse.class))) }) + public String updateLoanProduct(@PathParam("productId") @Parameter(description = "productId") final Long productId, + @Parameter(hidden = true) final String apiRequestBodyAsJson) { + + return getUpdateLoanProductResult(apiRequestBodyAsJson, productId); + } + + @GET + @Path("external-id/{externalProductId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Retrieve a Loan Product", description = "Retrieves a Loan Product\n\n" + "Example Requests:\n" + "\n" + + "loanproducts/external-id/2075e308-d4a8-44d9-8203-f5a947b8c2f4\n" + "\n" + "\n" + + "loanproducts/external-id/2075e308-d4a8-44d9-8203-f5a947b8c2f4?template=true\n" + "\n" + "\n" + + "loanproducts/external-id/2075e308-d4a8-44d9-8203-f5a947b8c2f4?fields=name,description,numberOfRepayments") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = LoanProductsApiResourceSwagger.GetLoanProductsProductIdResponse.class))) }) + public String retrieveLoanProductDetails( + @PathParam("externalProductId") @Parameter(description = "externalProductId") final String externalProductId, + @Context final UriInfo uriInfo) { + + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); + + ExternalId externalId = ExternalIdFactory.produce(externalProductId); + + Long productId = resolveProductId(externalId); + if (Objects.isNull(productId)) { + throw new LoanProductNotFoundException(externalId); + } + + return getLoanProductDetails(productId, uriInfo); + } + + @PUT + @Path("external-id/{externalProductId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Update a Loan Product", description = "Updates a Loan Product") + @RequestBody(required = true, content = @Content(schema = @Schema(implementation = LoanProductsApiResourceSwagger.PutLoanProductsProductIdRequest.class))) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = LoanProductsApiResourceSwagger.PutLoanProductsProductIdResponse.class))) }) + public String updateLoanProduct( + @PathParam("externalProductId") @Parameter(description = "externalProductId") final String externalProductId, + @Parameter(hidden = true) final String apiRequestBodyAsJson) { + + ExternalId externalId = ExternalIdFactory.produce(externalProductId); + + Long productId = resolveProductId(externalId); + + if (Objects.isNull(productId)) { + throw new LoanProductNotFoundException(externalId); + } + + return getUpdateLoanProductResult(apiRequestBodyAsJson, productId); + } + + private String getUpdateLoanProductResult(String apiRequestBodyAsJson, Long productId) { + final CommandWrapper commandRequest = new CommandWrapperBuilder().updateLoanProduct(productId).withJson(apiRequestBodyAsJson) + .build(); + + final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + + return this.toApiJsonSerializer.serialize(result); + } + + private Long resolveProductId(ExternalId externalProductId) { + return loanProductReadPlatformService.retrieveLoanProductByExternalId(externalProductId).getId(); + } + + private String getLoanProductDetails(Long productId, UriInfo uriInfo) { final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); LoanProductData loanProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId); @@ -256,25 +340,6 @@ public class LoanProductsApiResource { return this.toApiJsonSerializer.serialize(settings, loanProduct, LOAN_PRODUCT_DATA_PARAMETERS); } - @PUT - @Path("{productId}") - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) - @Operation(summary = "Update a Loan Product", description = "Updates a Loan Product") - @RequestBody(required = true, content = @Content(schema = @Schema(implementation = LoanProductsApiResourceSwagger.PutLoanProductsProductIdRequest.class))) - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = LoanProductsApiResourceSwagger.PutLoanProductsProductIdResponse.class))) }) - public String updateLoanProduct(@PathParam("productId") @Parameter(description = "productId") final Long productId, - @Parameter(hidden = true) final String apiRequestBodyAsJson) { - - final CommandWrapper commandRequest = new CommandWrapperBuilder().updateLoanProduct(productId).withJson(apiRequestBodyAsJson) - .build(); - - final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); - - return this.toApiJsonSerializer.serialize(result); - } - private LoanProductData handleTemplate(final LoanProductData productData) { Collection chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableFees(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java index 2626ac977..26fad80e1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java @@ -41,6 +41,8 @@ final class LoanProductsApiResourceSwagger { @Schema(example = "LP Accrual Accounting") public String name; + @Schema(example = "2075e308-d4a8-44d9-8203-f5a947b8c2f4") + public String externalId; @Schema(example = "LPAA") public String shortName; @Schema(example = "non-interest bearing product") diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRepository.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRepository.java index 64c93583d..68e912b04 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRepository.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProductRepository.java @@ -19,6 +19,7 @@ package org.apache.fineract.portfolio.loanproduct.domain; import java.util.List; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; @@ -33,4 +34,6 @@ public interface LoanProductRepository extends JpaRepository, Long countByDelinquencyBucket(DelinquencyBucket delinquencyBucket); List findByDelinquencyBucketNotNull(); + + LoanProduct findByExternalId(ExternalId externalId); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/exception/LoanProductNotFoundException.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/exception/LoanProductNotFoundException.java index 13b6ff69e..a4f1cbece 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/exception/LoanProductNotFoundException.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/exception/LoanProductNotFoundException.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.portfolio.loanproduct.exception; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; import org.springframework.dao.EmptyResultDataAccessException; @@ -30,6 +31,10 @@ public class LoanProductNotFoundException extends AbstractPlatformResourceNotFou super("error.msg.loanproduct.id.invalid", "Loan product with identifier " + id + " does not exist", id); } + public LoanProductNotFoundException(final ExternalId externalId) { + super("error.msg.loanproduct.id.invalid", "Loan product with identifier " + externalId + " does not exist", externalId); + } + public LoanProductNotFoundException(Long id, EmptyResultDataAccessException e) { super("error.msg.loanproduct.id.invalid", "Loan product with identifier " + id + " does not exist", id, e); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformService.java index 54df64fc7..27613d700 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformService.java @@ -19,8 +19,10 @@ package org.apache.fineract.portfolio.loanproduct.service; import java.util.Collection; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.portfolio.loanproduct.data.LoanProductBorrowerCycleVariationData; import org.apache.fineract.portfolio.loanproduct.data.LoanProductData; +import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; public interface LoanProductReadPlatformService { @@ -34,6 +36,8 @@ public interface LoanProductReadPlatformService { LoanProductData retrieveLoanProduct(Long productId); + LoanProduct retrieveLoanProductByExternalId(ExternalId externalId); + LoanProductData retrieveNewLoanProductDetails(); Collection retrieveAllLoanProductsForCurrency(String currencyCode); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java index 7122139c6..01cd94103 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java @@ -24,8 +24,10 @@ import java.sql.SQLException; import java.time.LocalDate; import java.util.ArrayList; import java.util.Collection; +import lombok.RequiredArgsConstructor; import org.apache.fineract.accounting.common.AccountingEnumerations; import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.core.domain.JdbcSupport; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator; @@ -42,19 +44,21 @@ import org.apache.fineract.portfolio.loanproduct.data.LoanProductBorrowerCycleVa import org.apache.fineract.portfolio.loanproduct.data.LoanProductData; import org.apache.fineract.portfolio.loanproduct.data.LoanProductGuaranteeData; import org.apache.fineract.portfolio.loanproduct.data.LoanProductInterestRecalculationData; +import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; import org.apache.fineract.portfolio.loanproduct.domain.LoanProductConfigurableAttributes; import org.apache.fineract.portfolio.loanproduct.domain.LoanProductParamType; +import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository; import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException; import org.apache.fineract.portfolio.rate.data.RateData; import org.apache.fineract.portfolio.rate.service.RateReadService; import org.jetbrains.annotations.NotNull; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Service; @Service +@RequiredArgsConstructor public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatformService { private final PlatformSecurityContext context; @@ -64,20 +68,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo private final DatabaseSpecificSQLGenerator sqlGenerator; private final FineractEntityAccessUtil fineractEntityAccessUtil; private final DelinquencyReadPlatformService delinquencyReadPlatformService; - - @Autowired - public LoanProductReadPlatformServiceImpl(final PlatformSecurityContext context, - final ChargeReadPlatformService chargeReadPlatformService, final JdbcTemplate jdbcTemplate, - final FineractEntityAccessUtil fineractEntityAccessUtil, final RateReadService rateReadService, - final DelinquencyReadPlatformService delinquencyReadPlatformService, final DatabaseSpecificSQLGenerator sqlGenerator) { - this.context = context; - this.chargeReadPlatformService = chargeReadPlatformService; - this.jdbcTemplate = jdbcTemplate; - this.fineractEntityAccessUtil = fineractEntityAccessUtil; - this.rateReadService = rateReadService; - this.sqlGenerator = sqlGenerator; - this.delinquencyReadPlatformService = delinquencyReadPlatformService; - } + private final LoanProductRepository loanProductRepository; @Override public LoanProductData retrieveLoanProduct(final Long loanProductId) { @@ -99,6 +90,11 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo } } + @Override + public LoanProduct retrieveLoanProductByExternalId(final ExternalId externalId) { + return loanProductRepository.findByExternalId(externalId); + } + @Override public Collection retrieveLoanProductBorrowerCycleVariations(final Long loanProductId) { final LoanProductBorrowerCycleMapper rm = new LoanProductBorrowerCycleMapper(); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductExternalIdTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductExternalIdTest.java new file mode 100644 index 000000000..03d327012 --- /dev/null +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductExternalIdTest.java @@ -0,0 +1,76 @@ +/** + * 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 static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +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.util.HashMap; +import java.util.UUID; +import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; +import org.apache.fineract.client.models.PutLoanProductsProductIdRequest; +import org.apache.fineract.client.models.PutLoanProductsProductIdResponse; +import org.apache.fineract.integrationtests.common.Utils; +import org.apache.fineract.integrationtests.common.loans.LoanProductHelper; +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; + +public class LoanProductExternalIdTest { + + private ResponseSpecification responseSpec; + private RequestSpecification requestSpec; + private LoanTransactionHelper loanTransactionHelper; + private LoanProductHelper loanProductHelper; + + @BeforeEach + public void setup() { + Utils.initializeRESTAssured(); + this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); + this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); + this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); + this.loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec); + this.loanProductHelper = new LoanProductHelper(); + } + + @Test + public void testLoanProductWithExternalId() { + String externalId = UUID.randomUUID().toString(); + HashMap request = new LoanProductTestBuilder().withExternalId(externalId).build(null, null); + Integer loanProductId = loanTransactionHelper.getLoanProductId(Utils.convertToJson(request)); + assertNotNull(loanProductId); + + GetLoanProductsProductIdResponse getLoanProductsProductIdResponse = loanProductHelper.retrieveLoanProductByExternalId(externalId); + assertNotNull(getLoanProductsProductIdResponse.getId()); + assertEquals(loanProductId, getLoanProductsProductIdResponse.getId().intValue()); + + final PutLoanProductsProductIdRequest requestModifyLoan = new PutLoanProductsProductIdRequest() + .shortName(Utils.uniqueRandomStringGenerator("", 3)); + PutLoanProductsProductIdResponse putLoanProductsProductIdResponse = loanProductHelper.updateLoanProductByExternalId(externalId, + requestModifyLoan); + assertNotNull(putLoanProductsProductIdResponse.getResourceId()); + assertEquals(loanProductId, putLoanProductsProductIdResponse.getResourceId().intValue()); + } +} diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductHelper.java index d3f0a1be3..46c7aa1ff 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductHelper.java @@ -18,8 +18,11 @@ */ package org.apache.fineract.integrationtests.common.loans; +import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; import org.apache.fineract.client.models.PostLoanProductsRequest; import org.apache.fineract.client.models.PostLoanProductsResponse; +import org.apache.fineract.client.models.PutLoanProductsProductIdRequest; +import org.apache.fineract.client.models.PutLoanProductsProductIdResponse; import org.apache.fineract.integrationtests.client.IntegrationTest; public class LoanProductHelper extends IntegrationTest { @@ -29,4 +32,12 @@ public class LoanProductHelper extends IntegrationTest { public PostLoanProductsResponse createLoanProduct(PostLoanProductsRequest request) { return ok(fineract().loanProducts.createLoanProduct(request)); } + + public GetLoanProductsProductIdResponse retrieveLoanProductByExternalId(String externalId) { + return ok(fineract().loanProducts.retrieveLoanProductDetails1(externalId)); + } + + public PutLoanProductsProductIdResponse updateLoanProductByExternalId(String externalId, PutLoanProductsProductIdRequest request) { + return ok(fineract().loanProducts.updateLoanProduct1(externalId, request)); + } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java index a13b01e6c..49c6c9181 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java @@ -76,6 +76,7 @@ public class LoanProductTestBuilder { private String nameOfLoanProduct = Utils.uniqueRandomStringGenerator("LOAN_PRODUCT_", 6); private String shortName = Utils.uniqueRandomStringGenerator("", 4); + private String externalId = null; private String principal = "10000.00"; private String numberOfRepayments = "5"; private String repaymentFrequency = MONTHS; @@ -160,6 +161,7 @@ public class LoanProductTestBuilder { } map.put("name", this.nameOfLoanProduct); map.put("shortName", this.shortName); + map.put("externalId", this.externalId); map.put("currencyCode", this.currencyCode); map.put("locale", LOCALE); map.put("dateFormat", "dd MMMM yyyy"); @@ -281,6 +283,11 @@ public class LoanProductTestBuilder { return map; } + public LoanProductTestBuilder withExternalId(String externalId) { + this.externalId = externalId; + return this; + } + public LoanProductTestBuilder withInstallmentAmountInMultiplesOf(String installmentAmountInMultiplesOf) { this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf; return this;