[FINERACT-1760] Loan product external id

This commit is contained in:
taskain7
2023-07-13 19:57:28 +02:00
committed by Adam Saghy
parent d65de7a8e9
commit be935cd55b
11 changed files with 222 additions and 40 deletions
@@ -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);
@@ -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<LoanProductBorrowerCycleVariations> 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<Charge> 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> 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;
}
@@ -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<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableFees();
@@ -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")
@@ -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<LoanProduct, Long>,
Long countByDelinquencyBucket(DelinquencyBucket delinquencyBucket);
List<LoanProduct> findByDelinquencyBucketNotNull();
LoanProduct findByExternalId(ExternalId externalId);
}
@@ -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);
}
@@ -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<LoanProductData> retrieveAllLoanProductsForCurrency(String currencyCode);
@@ -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<LoanProductBorrowerCycleVariationData> retrieveLoanProductBorrowerCycleVariations(final Long loanProductId) {
final LoanProductBorrowerCycleMapper rm = new LoanProductBorrowerCycleMapper();
@@ -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<String, Object> 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());
}
}
@@ -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));
}
}
@@ -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;