FINERACT-2247: New command processing - Currency Management (org.apache.fineract.organisation.monetary)

This commit is contained in:
viktorpavlenko
2025-06-28 10:38:32 +02:00
committed by Aleksandar Vidakovic
parent 0629bb2d48
commit 4c3da5b06a
42 changed files with 404 additions and 538 deletions
@@ -22,7 +22,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import org.apache.fineract.organisation.monetary.api.CurrenciesApiResourceSwagger.CurrencyItem;
import org.apache.fineract.portfolio.note.data.NoteData;
import org.apache.fineract.portfolio.paymenttype.api.PaymentTypeApiResourceSwagger.GetPaymentTypesResponse;
@@ -69,6 +68,26 @@ final class JournalEntriesApiResourceSwagger {
public Long officeId;
}
public static final class CurrencyItem {
private CurrencyItem() {}
@Schema(example = "USD")
public String code;
@Schema(example = "US Dollar")
public String name;
@Schema(example = "2")
public Integer decimalPlaces;
@Schema(example = "100")
public Integer inMultiplesOf;
@Schema(example = "$")
public String displaySymbol;
@Schema(example = "currency.USD")
public String nameCode;
@Schema(example = "US Dollar ($)")
public String displayLabel;
}
static final class EnumOptionType {
private EnumOptionType() {}
@@ -147,6 +147,11 @@ public class SecurityConfig {
.hasAnyAuthority("ALL_FUNCTIONS", "ALL_FUNCTIONS_READ", "READ_CACHE")
.requestMatchers(antMatcher(HttpMethod.PUT, "/api/*/caches"))
.hasAnyAuthority("ALL_FUNCTIONS", "ALL_FUNCTIONS_WRITE", "UPDATE_CACHE")
// currency
.requestMatchers(antMatcher(HttpMethod.GET, "/api/*/currencies"))
.hasAnyAuthority("ALL_FUNCTIONS", "ALL_FUNCTIONS_READ", "READ_CURRENCY")
.requestMatchers(antMatcher(HttpMethod.POST, "/api/*/currencies"))
.hasAnyAuthority("ALL_FUNCTIONS", "ALL_FUNCTIONS_WRITE", "UPDATE_CURRENCY")
// ...
.requestMatchers(antMatcher(HttpMethod.POST, "/api/*/twofactor/validate")).fullyAuthenticated() //
.requestMatchers(antMatcher("/api/*/twofactor")).fullyAuthenticated() //
@@ -61,7 +61,7 @@ public class LoanRepaymentBusinessEventSerializer extends AbstractBusinessEventW
String externalId = loan.getExternalId().getValue();
MonetaryCurrency loanCurrency = loan.getCurrency();
CurrencyDataV1 currency = CurrencyDataV1.newBuilder().setCode(loanCurrency.getCode())
.setDecimalPlaces(loanCurrency.getDigitsAfterDecimal()).setInMultiplesOf(loanCurrency.getCurrencyInMultiplesOf()).build();
.setDecimalPlaces(loanCurrency.getDigitsAfterDecimal()).setInMultiplesOf(loanCurrency.getInMultiplesOf()).build();
RepaymentDueDataV1 repaymentDue = getRepaymentDueData(repaymentInstallment, loanCurrency);
@@ -1,88 +0,0 @@
/**
* 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.organisation.monetary.api;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.domain.CommandWrapper;
import org.apache.fineract.commands.service.CommandWrapperBuilder;
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.monetary.data.ApplicationCurrencyConfigurationData;
import org.apache.fineract.organisation.monetary.data.request.CurrencyRequest;
import org.apache.fineract.organisation.monetary.service.OrganisationCurrencyReadPlatformService;
import org.springframework.stereotype.Component;
@Path("/v1/currencies")
@Component
@Tag(name = "Currency", description = "Application related configuration around viewing/updating the currencies permitted for use within the MFI.")
@RequiredArgsConstructor
public class CurrenciesApiResource {
private static final String RESOURCE_NAME_FOR_PERMISSIONS = "CURRENCY";
private final PlatformSecurityContext context;
private final OrganisationCurrencyReadPlatformService readPlatformService;
private final DefaultToApiJsonSerializer<ApplicationCurrencyConfigurationData> toApiJsonSerializer;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Retrieve Currency Configuration", description = "Returns the list of currencies permitted for use AND the list of currencies not selected (but available for selection).\n"
+ "\n" + "Example Requests:\n" + "\n" + "currencies\n" + "\n" + "\n" + "currencies?fields=selectedCurrencyOptions")
public ApplicationCurrencyConfigurationData retrieveCurrencies() {
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
return this.readPlatformService.retrieveCurrencyConfiguration();
}
@PUT
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Update Currency Configuration", description = "Updates the list of currencies permitted for use.")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = CurrencyRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CurrenciesApiResourceSwagger.PutCurrenciesResponse.class))) })
public CommandProcessingResult updateCurrencies(@Parameter(hidden = true) CurrencyRequest currencyRequest) {
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
.updateCurrencies() //
.withJson(toApiJsonSerializer.serialize(currencyRequest)) //
.build();
return this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
}
}
@@ -1,63 +0,0 @@
/**
* 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.organisation.monetary.api;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* Created by sanyam on 14/8/17.
*/
public final class CurrenciesApiResourceSwagger {
private CurrenciesApiResourceSwagger() {
}
public static final class CurrencyItem {
private CurrencyItem() {}
@Schema(example = "USD")
public String code;
@Schema(example = "US Dollar")
public String name;
@Schema(example = "2")
public Integer decimalPlaces;
@Schema(example = "100")
public Integer inMultiplesOf;
@Schema(example = "$")
public String displaySymbol;
@Schema(example = "currency.USD")
public String nameCode;
@Schema(example = "US Dollar ($)")
public String displayLabel;
}
@Schema(description = "PutCurrenciesResponse")
public static final class PutCurrenciesResponse {
private PutCurrenciesResponse() {
}
@Schema(example = "[\"KES\",\n" + " \"BND\",\n" + " \"LBP\",\n" + " \"GHC\",\n" + " \"USD\",\n"
+ " \"XOF\",\n" + " \"AED\",\n" + " \"AMD\"]")
public String[] currencies;
}
}
@@ -1,47 +0,0 @@
/**
* 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.organisation.monetary.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.organisation.monetary.service.CurrencyWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "CURRENCY", action = "UPDATE")
public class UpdateCurrencyCommandHandler implements NewCommandSourceHandler {
private final CurrencyWritePlatformService writePlatformService;
@Autowired
public UpdateCurrencyCommandHandler(final CurrencyWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.writePlatformService.updateAllowedCurrencies(command);
}
}
@@ -20,21 +20,16 @@ package org.apache.fineract.organisation.monetary.service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.monetary.data.CurrencyUpdateRequest;
import org.apache.fineract.organisation.monetary.data.CurrencyUpdateResponse;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
import org.apache.fineract.organisation.monetary.domain.OrganisationCurrency;
import org.apache.fineract.organisation.monetary.domain.OrganisationCurrencyRepository;
import org.apache.fineract.organisation.monetary.exception.CurrencyInUseException;
import org.apache.fineract.organisation.monetary.serialization.CurrencyCommandFromApiJsonDeserializer;
import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
import org.apache.fineract.portfolio.loanproduct.service.LoanProductReadPlatformService;
import org.apache.fineract.portfolio.savings.service.SavingsProductReadPlatformService;
@@ -43,30 +38,22 @@ import org.springframework.transaction.annotation.Transactional;
@RequiredArgsConstructor
public class CurrencyWritePlatformServiceJpaRepositoryImpl implements CurrencyWritePlatformService {
private final PlatformSecurityContext context;
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository;
private final OrganisationCurrencyRepository organisationCurrencyRepository;
private final CurrencyCommandFromApiJsonDeserializer fromApiJsonDeserializer;
private final LoanProductReadPlatformService loanProductService;
private final SavingsProductReadPlatformService savingsProductService;
private final ChargeReadPlatformService chargeService;
@Transactional
@Override
public CommandProcessingResult updateAllowedCurrencies(final JsonCommand command) {
public CurrencyUpdateResponse updateAllowedCurrencies(final CurrencyUpdateRequest request) {
final var currencies = request.getCurrencies();
this.context.authenticatedUser();
this.fromApiJsonDeserializer.validateForUpdate(command.json());
final String[] currencies = command.arrayValueOfParameterNamed("currencies");
final Map<String, Object> changes = new LinkedHashMap<>();
final List<String> allowedCurrencyCodes = new ArrayList<>();
final Set<OrganisationCurrency> allowedCurrencies = new HashSet<>();
for (final String currencyCode : currencies) {
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currencyCode);
final ApplicationCurrency currency = applicationCurrencyRepository.findOneWithNotFoundDetection(currencyCode);
final OrganisationCurrency allowedCurrency = currency.toOrganisationCurrency();
@@ -74,9 +61,9 @@ public class CurrencyWritePlatformServiceJpaRepositoryImpl implements CurrencyWr
allowedCurrencies.add(allowedCurrency);
}
for (OrganisationCurrency priorCurrency : this.organisationCurrencyRepository.findAll()) {
for (OrganisationCurrency priorCurrency : organisationCurrencyRepository.findAll()) {
if (!allowedCurrencyCodes.contains(priorCurrency.getCode())) {
// Check if it's safe to remove this currency.
// check if it's safe to remove this currency.
if (!loanProductService.retrieveAllLoanProductsForCurrency(priorCurrency.getCode()).isEmpty()
|| !savingsProductService.retrieveAllForCurrency(priorCurrency.getCode()).isEmpty()
|| !chargeService.retrieveAllChargesForCurrency(priorCurrency.getCode()).isEmpty()) {
@@ -85,14 +72,9 @@ public class CurrencyWritePlatformServiceJpaRepositoryImpl implements CurrencyWr
}
}
changes.put("currencies", allowedCurrencyCodes.toArray(new String[allowedCurrencyCodes.size()]));
organisationCurrencyRepository.deleteAll();
organisationCurrencyRepository.saveAll(allowedCurrencies);
this.organisationCurrencyRepository.deleteAll();
this.organisationCurrencyRepository.saveAll(allowedCurrencies);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.with(changes) //
.build();
return CurrencyUpdateResponse.builder().currencies(allowedCurrencyCodes).build();
}
}
@@ -18,10 +18,8 @@
*/
package org.apache.fineract.organisation.monetary.starter;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
import org.apache.fineract.organisation.monetary.domain.OrganisationCurrencyRepository;
import org.apache.fineract.organisation.monetary.serialization.CurrencyCommandFromApiJsonDeserializer;
import org.apache.fineract.organisation.monetary.service.CurrencyReadPlatformService;
import org.apache.fineract.organisation.monetary.service.CurrencyReadPlatformServiceImpl;
import org.apache.fineract.organisation.monetary.service.CurrencyWritePlatformService;
@@ -41,19 +39,17 @@ public class OrganisationMonetaryConfiguration {
@Bean
@ConditionalOnMissingBean(CurrencyReadPlatformService.class)
public CurrencyReadPlatformService currencyReadPlatformService(PlatformSecurityContext context, JdbcTemplate jdbcTemplate) {
return new CurrencyReadPlatformServiceImpl(context, jdbcTemplate);
public CurrencyReadPlatformService currencyReadPlatformService(JdbcTemplate jdbcTemplate) {
return new CurrencyReadPlatformServiceImpl(jdbcTemplate);
}
@Bean
@ConditionalOnMissingBean(CurrencyWritePlatformService.class)
public CurrencyWritePlatformService currencyWritePlatformService(PlatformSecurityContext context,
ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
OrganisationCurrencyRepository organisationCurrencyRepository, CurrencyCommandFromApiJsonDeserializer fromApiJsonDeserializer,
LoanProductReadPlatformService loanProductService, SavingsProductReadPlatformService savingsProductService,
ChargeReadPlatformService chargeService) {
return new CurrencyWritePlatformServiceJpaRepositoryImpl(context, applicationCurrencyRepository, organisationCurrencyRepository,
fromApiJsonDeserializer, loanProductService, savingsProductService, chargeService);
public CurrencyWritePlatformService currencyWritePlatformService(ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
OrganisationCurrencyRepository organisationCurrencyRepository, LoanProductReadPlatformService loanProductService,
SavingsProductReadPlatformService savingsProductService, ChargeReadPlatformService chargeService) {
return new CurrencyWritePlatformServiceJpaRepositoryImpl(applicationCurrencyRepository, organisationCurrencyRepository,
loanProductService, savingsProductService, chargeService);
}
@Bean
@@ -1,55 +0,0 @@
/**
* 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.portfolio.group.data;
import java.util.Collection;
import org.apache.fineract.organisation.monetary.data.MoneyData;
public class GroupSummary {
private final Long totalActiveClients;
private final Long totalChildGroups;
private final Collection<MoneyData> totalLoanPortfolio;
private final Collection<MoneyData> totalSavings;
public GroupSummary(final Long totalActiveClients, final Long totalChildGroups, final Collection<MoneyData> totalLoanPortfolio,
final Collection<MoneyData> totalSavings) {
this.totalActiveClients = totalActiveClients;
this.totalChildGroups = totalChildGroups;
this.totalLoanPortfolio = totalLoanPortfolio;
this.totalSavings = totalSavings;
}
public Long getTotalActiveClients() {
return this.totalActiveClients;
}
public Long getTotalChildGroups() {
return this.totalChildGroups;
}
public Collection<MoneyData> getTotalLoanPortfolio() {
return this.totalLoanPortfolio;
}
public Collection<MoneyData> getTotalSavings() {
return this.totalSavings;
}
}
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.data;
import lombok.Data;
import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.organisation.monetary.mapper.CurrencyMapper;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.mapstruct.Mapping;
@@ -50,7 +51,7 @@ public class LoanPointInTimeData {
private Long loanProductId;
private String loanProductName;
@org.mapstruct.Mapper(config = MapstructMapperConfig.class, uses = { LoanStatusEnumData.Mapper.class, CurrencyData.Mapper.class,
@org.mapstruct.Mapper(config = MapstructMapperConfig.class, uses = { LoanStatusEnumData.Mapper.class, CurrencyMapper.class,
LoanPrincipalData.Mapper.class, LoanInterestData.Mapper.class, LoanFeeData.Mapper.class, LoanPenaltyData.Mapper.class,
LoanTotalAmountData.Mapper.class })
public interface Mapper {
@@ -568,7 +568,7 @@ public class LoanAssemblerImpl implements LoanAssembler {
changes.put(LoanApiConstants.productIdParameterName, newValue);
loan.updateLoanProduct(loanProduct);
final MonetaryCurrency currency = new MonetaryCurrency(loanProduct.getCurrency().getCode(),
loanProduct.getCurrency().getDigitsAfterDecimal(), loanProduct.getCurrency().getCurrencyInMultiplesOf());
loanProduct.getCurrency().getDigitsAfterDecimal(), loanProduct.getCurrency().getInMultiplesOf());
loan.getLoanRepaymentScheduleDetail().setCurrency(currency);
if (!changes.containsKey(LoanApiConstants.interestRateFrequencyTypeParameterName)) {
@@ -55,7 +55,7 @@ public class LoanProductRelatedDetailUpdateUtil {
String currencyCode = loanRepaymentScheduleDetail.getCurrency().getCode();
Integer digitsAfterDecimal = loanRepaymentScheduleDetail.getCurrency().getDigitsAfterDecimal();
Integer inMultiplesOf = loanRepaymentScheduleDetail.getCurrency().getCurrencyInMultiplesOf();
Integer inMultiplesOf = loanRepaymentScheduleDetail.getCurrency().getInMultiplesOf();
final String digitsAfterDecimalParamName = "digitsAfterDecimal";
if (command.isChangeInIntegerParameterNamed(digitsAfterDecimalParamName, digitsAfterDecimal)) {
@@ -173,8 +173,8 @@ public class LoanAccountDelinquencyRangeEventSerializerTest {
when(loanAccountData.getAccountNo()).thenReturn("0001");
when(loanAccountData.getExternalId()).thenReturn(ExternalIdFactory.produce("externalId"));
when(loanAccountData.getDelinquencyRange()).thenReturn(new DelinquencyRangeData(1L, "classification", 1, 10));
when(loanAccountData.getCurrency()).thenAnswer(a -> new CurrencyData(loanCurrency.getCode(), loanCurrency.getDigitsAfterDecimal(),
loanCurrency.getCurrencyInMultiplesOf()));
when(loanAccountData.getCurrency()).thenAnswer(
a -> new CurrencyData(loanCurrency.getCode(), loanCurrency.getDigitsAfterDecimal(), loanCurrency.getInMultiplesOf()));
when(loanForProcessing.getCurrency()).thenReturn(loanCurrency);
when(loanForProcessing.isEnableInstallmentLevelDelinquency()).thenReturn(false);
when(delinquentData.getDelinquentDate()).thenReturn(delinquentDate);
@@ -238,8 +238,8 @@ public class LoanAccountDelinquencyRangeEventSerializerTest {
when(loanAccountData.getAccountNo()).thenReturn("0001");
when(loanAccountData.getExternalId()).thenReturn(ExternalIdFactory.produce("externalId"));
when(loanAccountData.getDelinquencyRange()).thenReturn(new DelinquencyRangeData(1L, "classification", 1, 10));
when(loanAccountData.getCurrency()).thenAnswer(a -> new CurrencyData(loanCurrency.getCode(), loanCurrency.getDigitsAfterDecimal(),
loanCurrency.getCurrencyInMultiplesOf()));
when(loanAccountData.getCurrency()).thenAnswer(
a -> new CurrencyData(loanCurrency.getCode(), loanCurrency.getDigitsAfterDecimal(), loanCurrency.getInMultiplesOf()));
when(loanForProcessing.getCurrency()).thenReturn(loanCurrency);
when(loanForProcessing.isEnableInstallmentLevelDelinquency()).thenReturn(true);
when(delinquentData.getDelinquentDate()).thenReturn(delinquentDate);