Fineract-1964: Add functionality to calculate maturity amount before creating FD account
This commit is contained in:
committed by
Adam Saghy
parent
3753d89444
commit
86bd2763f0
+18
-1
@@ -112,6 +112,11 @@ public final class DepositsApiConstants {
|
||||
public static final String routingCodeParamName = "routingCode";
|
||||
public static final String receiptNumberParamName = "receiptNumber";
|
||||
public static final String bankNumberParamName = "bankNumber";
|
||||
public static final String principalAmountParamName = "principalAmount";
|
||||
public static final String annualInterestRateParamName = "annualInterestRate";
|
||||
public static final String interestPostingPeriodInMonthsParamName = "interestPostingPeriodInMonths";
|
||||
public static final String tenureInMonthsParamName = "tenureInMonths";
|
||||
public static final String interestCompoundingPeriodInMonthsParamName = "interestCompoundingPeriodInMonths";
|
||||
|
||||
// Preclosure parameters
|
||||
public static final String preClosurePenalApplicableParamName = "preClosurePenalApplicable";
|
||||
@@ -307,10 +312,22 @@ public final class DepositsApiConstants {
|
||||
|
||||
public static final Set<String> FIXED_DEPOSIT_ACCOUNT_REQUEST_DATA_PARAMETERS = fixedDepositAccountRequestData();
|
||||
public static final Set<String> FIXED_DEPOSIT_ACCOUNT_RESPONSE_DATA_PARAMETERS = fixedDepositAccountResponseData();
|
||||
|
||||
public static final Set<String> FIXED_DEPOSIT_ACCOUNT_INTEREST_CALCULATION_PARAMETERS = fixedDepositInterestCalculationData();
|
||||
public static final Set<String> RECURRING_DEPOSIT_ACCOUNT_REQUEST_DATA_PARAMETERS = recurringDepositAccountRequestData();
|
||||
public static final Set<String> RECURRING_DEPOSIT_ACCOUNT_RESPONSE_DATA_PARAMETERS = recurringDepositAccountResponseData();
|
||||
|
||||
private static Set<String> fixedDepositInterestCalculationData() {
|
||||
final Set<String> fixedDepositInterestCalculationData = new HashSet<>();
|
||||
fixedDepositInterestCalculationData.add(principalAmountParamName);
|
||||
fixedDepositInterestCalculationData.add(annualInterestRateParamName);
|
||||
fixedDepositInterestCalculationData.add(tenureInMonthsParamName);
|
||||
fixedDepositInterestCalculationData.add(interestPostingPeriodInMonthsParamName);
|
||||
fixedDepositInterestCalculationData.add(interestCompoundingPeriodInMonthsParamName);
|
||||
|
||||
return fixedDepositInterestCalculationData;
|
||||
|
||||
}
|
||||
|
||||
private static Set<String> fixedDepositAccountRequestData() {
|
||||
final Set<String> fixedDepositRequestData = new HashSet<>();
|
||||
fixedDepositRequestData.addAll(DEPOSIT_ACCOUNT_REQUEST_DATA_PARAMETERS);
|
||||
|
||||
+30
@@ -46,6 +46,7 @@ import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -79,6 +80,7 @@ import org.apache.fineract.portfolio.savings.data.SavingsAccountChargeData;
|
||||
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData;
|
||||
import org.apache.fineract.portfolio.savings.service.DepositAccountPreMatureCalculationPlatformService;
|
||||
import org.apache.fineract.portfolio.savings.service.DepositAccountReadPlatformService;
|
||||
import org.apache.fineract.portfolio.savings.service.FixedDepositAccountInterestCalculationService;
|
||||
import org.apache.fineract.portfolio.savings.service.SavingsAccountChargeReadPlatformService;
|
||||
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
|
||||
import org.glassfish.jersey.media.multipart.FormDataParam;
|
||||
@@ -102,6 +104,7 @@ public class FixedDepositAccountsApiResource {
|
||||
private final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService;
|
||||
private final BulkImportWorkbookService bulkImportWorkbookService;
|
||||
private final BulkImportWorkbookPopulatorService bulkImportWorkbookPopulatorService;
|
||||
private final FixedDepositAccountInterestCalculationService fixedDepositAccountInterestCalculationService;
|
||||
|
||||
@GET
|
||||
@Path("template")
|
||||
@@ -208,6 +211,33 @@ public class FixedDepositAccountsApiResource {
|
||||
DepositsApiConstants.FIXED_DEPOSIT_ACCOUNT_RESPONSE_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("calculate-fd-interest")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = FixedDepositAccountsApiResourceSwagger.CalculateFixedDepositInterestResponse.class))) })
|
||||
public String calculateFixedDepositInterest(@Context final UriInfo uriInfo,
|
||||
@QueryParam("principalAmount") @Parameter(description = "BigDecimal principalAmount") final BigDecimal principalAmount,
|
||||
@QueryParam("annualInterestRate") @Parameter(description = "annualInterestRate") final BigDecimal annualInterestRate,
|
||||
@QueryParam("tenureInMonths") @Parameter(description = "tenureInMonths") final Long tenureInMonths,
|
||||
@QueryParam("interestCompoundingPeriodInMonths") @Parameter(description = "interestCompoundingPeriodInMonths") final Long interestCompoundingPeriodInMonths,
|
||||
@QueryParam("interestPostingPeriodInMonths") @Parameter(description = "interestPostingPeriodInMonths") final Long interestPostingPeriodInMonths) {
|
||||
HashMap request = new HashMap<>();
|
||||
request.put("annualInterestRate", annualInterestRate);
|
||||
request.put("tenureInMonths", tenureInMonths);
|
||||
request.put("interestCompoundingPeriodInMonths", interestCompoundingPeriodInMonths);
|
||||
request.put("interestPostingPeriodInMonths", interestPostingPeriodInMonths);
|
||||
request.put("principalAmount", principalAmount);
|
||||
String apiRequestBodyAsJson = toApiJsonSerializer.serialize(request);
|
||||
JsonElement jsonElement = fromJsonHelper.parse(apiRequestBodyAsJson);
|
||||
HashMap result = fixedDepositAccountInterestCalculationService
|
||||
.calculateInterest(new JsonQuery(apiRequestBodyAsJson, jsonElement, fromJsonHelper));
|
||||
|
||||
return toApiJsonSerializer.serializeResult(result);
|
||||
|
||||
}
|
||||
|
||||
private BigDecimal getActivationCharge(Long accountId) {
|
||||
BigDecimal activationCharge = BigDecimal.ZERO;
|
||||
Collection<SavingsAccountChargeData> savingCharges = this.savingsAccountChargeReadPlatformService
|
||||
|
||||
+31
@@ -19,6 +19,7 @@
|
||||
package org.apache.fineract.portfolio.savings.api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -256,6 +257,36 @@ final class FixedDepositAccountsApiResourceSwagger {
|
||||
public GetFixedDepositAccountsDepositPeriodFrequency depositPeriodFrequency;
|
||||
}
|
||||
|
||||
@Schema(description = "CalculateFixedDepositInterestRequest")
|
||||
public static final class CalculateFixedDepositInterestRequest {
|
||||
|
||||
private CalculateFixedDepositInterestRequest() {}
|
||||
|
||||
@Schema(example = "10000")
|
||||
public BigDecimal principalAmount;
|
||||
@Schema(example = "5")
|
||||
public BigDecimal annualInterestRate;
|
||||
@Schema(example = "12")
|
||||
public Long tenureInMonths;
|
||||
@Schema(example = "3")
|
||||
public Long interestPostingPeriodInMonths;
|
||||
@Schema(example = "1")
|
||||
public Long interestCompoundingPeriodInMonths;
|
||||
|
||||
}
|
||||
|
||||
@Schema(description = "CalculateFixedDepositInterestResponse")
|
||||
public static final class CalculateFixedDepositInterestResponse {
|
||||
|
||||
private CalculateFixedDepositInterestResponse() {}
|
||||
|
||||
@Schema(example = "10511.61")
|
||||
public BigDecimal maturityAmount;
|
||||
|
||||
@Schema(example = "Accuracy Warning")
|
||||
public String warning;
|
||||
}
|
||||
|
||||
@Schema(description = "PostFixedDepositAccountsRequest")
|
||||
public static final class PostFixedDepositAccountsRequest {
|
||||
|
||||
|
||||
+56
@@ -20,11 +20,14 @@ package org.apache.fineract.portfolio.savings.data;
|
||||
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.adjustAdvanceTowardsFuturePaymentsParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.allowWithdrawalParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.annualInterestRateParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.depositAmountParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.depositPeriodFrequencyIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.depositPeriodParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.inMultiplesOfDepositTermParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.inMultiplesOfDepositTermTypeIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.interestCompoundingPeriodInMonthsParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.interestPostingPeriodInMonthsParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.isCalendarInheritedParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.isMandatoryDepositParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.linkedAccountParamName;
|
||||
@@ -37,8 +40,10 @@ import static org.apache.fineract.portfolio.savings.DepositsApiConstants.minDepo
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.preClosurePenalApplicableParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.preClosurePenalInterestOnTypeIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.preClosurePenalInterestParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.principalAmountParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.recurringFrequencyParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.recurringFrequencyTypeParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.tenureInMonthsParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.transferInterestToSavingsParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.transferToSavingsIdParamName;
|
||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.accountNoParamName;
|
||||
@@ -201,6 +206,23 @@ public class DepositAccountDataValidator {
|
||||
|
||||
}
|
||||
|
||||
public void validateFixedDepositForInterestCalculation(final String json) {
|
||||
if (StringUtils.isBlank(json)) {
|
||||
throw new InvalidJsonException();
|
||||
}
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,
|
||||
DepositsApiConstants.FIXED_DEPOSIT_ACCOUNT_INTEREST_CALCULATION_PARAMETERS);
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(DepositsApiConstants.FIXED_DEPOSIT_ACCOUNT_RESOURCE_NAME);
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
validateForInterestCalc(element, baseDataValidator);
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
|
||||
}
|
||||
|
||||
private void validateDepositDetailsForSubmit(final JsonElement element, final DataValidatorBuilder baseDataValidator) {
|
||||
|
||||
final Long clientId = this.fromApiJsonHelper.extractLongNamed(clientIdParamName, element);
|
||||
@@ -582,6 +604,40 @@ public class DepositAccountDataValidator {
|
||||
}
|
||||
}
|
||||
|
||||
private void validateForInterestCalc(final JsonElement element, final DataValidatorBuilder baseDataValidator) {
|
||||
|
||||
BigDecimal principalAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(principalAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(principalAmountParamName).value(principalAmount).notNull().positiveAmount();
|
||||
|
||||
BigDecimal annualInterestRate = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(annualInterestRateParamName, element);
|
||||
baseDataValidator.reset().parameter(annualInterestRateParamName).value(annualInterestRate).notNull()
|
||||
.notLessThanMin(BigDecimal.valueOf(0));
|
||||
|
||||
Long tenureInMonths = this.fromApiJsonHelper.extractLongNamed(tenureInMonthsParamName, element);
|
||||
baseDataValidator.reset().parameter(tenureInMonthsParamName).value(tenureInMonths).notNull().longGreaterThanZero();
|
||||
|
||||
Long interestPostingPeriodInMonths = this.fromApiJsonHelper.extractLongNamed(interestPostingPeriodInMonthsParamName, element);
|
||||
baseDataValidator.reset().parameter(interestPostingPeriodInMonthsParamName).value(interestPostingPeriodInMonths).notNull()
|
||||
.longGreaterThanZero();
|
||||
|
||||
Long interestCompoundingPeriodInMonths = this.fromApiJsonHelper.extractLongNamed(interestCompoundingPeriodInMonthsParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(interestCompoundingPeriodInMonthsParamName).value(interestCompoundingPeriodInMonths).notNull();
|
||||
|
||||
List<Long> allowedValues = List.of(1L, 2L, 3L, 4L, 6L, 12L);
|
||||
if (interestCompoundingPeriodInMonths != null && !allowedValues.contains(interestCompoundingPeriodInMonths)) {
|
||||
baseDataValidator.reset().parameter(interestCompoundingPeriodInMonthsParamName).value(interestCompoundingPeriodInMonths)
|
||||
.failWithCode("parameter.value.error", "interestCompoundingPeriodInMonths can only be one {1,2,3,4,6,12}");
|
||||
}
|
||||
if (interestCompoundingPeriodInMonths != null && tenureInMonths != null
|
||||
&& tenureInMonths % interestCompoundingPeriodInMonths != 0) {
|
||||
baseDataValidator.reset().parameter(interestCompoundingPeriodInMonthsParamName).value(interestCompoundingPeriodInMonths)
|
||||
.failWithCode("parameter.relational.validation",
|
||||
"tenureInMonths must be perfectly divisible by interestCompoundingPeriodInMonths");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void validateRecurringDetailForSubmit(final JsonElement element, final DataValidatorBuilder baseDataValidator) {
|
||||
|
||||
final BigDecimal mandatoryRecommendedDepositAmount = fromApiJsonHelper
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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.savings.service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonQuery;
|
||||
|
||||
public interface FixedDepositAccountInterestCalculationService {
|
||||
|
||||
HashMap calculateInterest(JsonQuery query);
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* 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.savings.service;
|
||||
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.annualInterestRateParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.interestCompoundingPeriodInMonthsParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.principalAmountParamName;
|
||||
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.tenureInMonthsParamName;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.util.HashMap;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonQuery;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
||||
import org.apache.fineract.portfolio.savings.data.DepositAccountDataValidator;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class FixedDepositAccountInterestCalculationServiceImpl implements FixedDepositAccountInterestCalculationService {
|
||||
|
||||
private final DepositAccountDataValidator depositAccountDataValidator;
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@Override
|
||||
public HashMap calculateInterest(JsonQuery query) {
|
||||
depositAccountDataValidator.validateFixedDepositForInterestCalculation(query.json());
|
||||
JsonElement element = query.parsedJson();
|
||||
BigDecimal principalAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(principalAmountParamName, element);
|
||||
BigDecimal annualInterestRate = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(annualInterestRateParamName, element);
|
||||
Long tenureInMonths = this.fromApiJsonHelper.extractLongNamed(tenureInMonthsParamName, element);
|
||||
Long interestCompoundingPeriodInMonths = this.fromApiJsonHelper.extractLongNamed(interestCompoundingPeriodInMonthsParamName,
|
||||
element);
|
||||
BigDecimal maturityAmount = this.calculateInterestInternal(principalAmount, annualInterestRate, tenureInMonths,
|
||||
interestCompoundingPeriodInMonths);
|
||||
String warning = "This is an approximate calculated amount - it may vary slightly when the account is created";
|
||||
|
||||
HashMap result = new HashMap<>();
|
||||
result.put("maturityAmount", maturityAmount);
|
||||
result.put("warning", warning);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public BigDecimal calculateInterestInternal(BigDecimal principalAmount, BigDecimal annualInterestRate, Long tenureInMonths,
|
||||
Long interestCompoundingPeriodInMonths) {
|
||||
BigDecimal numberOfCompoundingsPerAnnum = BigDecimal.valueOf(12).divide(BigDecimal.valueOf(interestCompoundingPeriodInMonths));
|
||||
Long totalNumberOfCompoundings = tenureInMonths / interestCompoundingPeriodInMonths;
|
||||
MathContext mc = MoneyHelper.getMathContext();
|
||||
BigDecimal exponentialTerm = annualInterestRate.divide(numberOfCompoundingsPerAnnum, mc).divide(BigDecimal.valueOf(100), mc)
|
||||
.add(BigDecimal.valueOf(1)).pow(Math.toIntExact(totalNumberOfCompoundings));
|
||||
return principalAmount.multiply(exponentialTerm);
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* 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.savings.service;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
||||
import org.apache.fineract.portfolio.savings.data.DepositAccountDataValidator;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class FixedDepositAccountInterestCalculationServiceImplTest {
|
||||
|
||||
private FixedDepositAccountInterestCalculationServiceImpl service;
|
||||
|
||||
@Mock
|
||||
private DepositAccountDataValidator depositAccountDataValidator;
|
||||
@Mock
|
||||
private FromJsonHelper fromApiJsonHelper;
|
||||
private MockedStatic<MoneyHelper> moneyHelperStatic;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
moneyHelperStatic = Mockito.mockStatic(MoneyHelper.class);
|
||||
moneyHelperStatic.when(() -> MoneyHelper.getMathContext()).thenReturn(new MathContext(12, RoundingMode.UP));
|
||||
service = new FixedDepositAccountInterestCalculationServiceImpl(depositAccountDataValidator, fromApiJsonHelper);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void deregister() {
|
||||
moneyHelperStatic.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculateInterestInternal1() {
|
||||
|
||||
// Calculate interest
|
||||
BigDecimal expectedInterest = new BigDecimal("10509.4533691406250000"); // Expected interest calculated based
|
||||
// on provided values
|
||||
BigDecimal calculatedInterest = service.calculateInterestInternal(BigDecimal.valueOf(10000), BigDecimal.valueOf(5), 12L, 3L);
|
||||
|
||||
// Verify the result
|
||||
assertEquals(expectedInterest, calculatedInterest);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculateInterestInternal2() {
|
||||
|
||||
// Calculate interest
|
||||
BigDecimal expectedInterest = new BigDecimal("105.062500"); // Expected interest calculated based on provided
|
||||
// values
|
||||
BigDecimal calculatedInterest = service.calculateInterestInternal(BigDecimal.valueOf(100), BigDecimal.valueOf(5), 12L, 6L);
|
||||
|
||||
// Verify the result
|
||||
assertEquals(expectedInterest, calculatedInterest);
|
||||
}
|
||||
|
||||
}
|
||||
+94
@@ -20,14 +20,19 @@ package org.apache.fineract.integrationtests;
|
||||
|
||||
import static java.time.temporal.ChronoUnit.DAYS;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import com.google.common.truth.Truth;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
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.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
@@ -44,6 +49,9 @@ import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.FinancialActivity;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonQuery;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||
import org.apache.fineract.integrationtests.common.CommonConstants;
|
||||
import org.apache.fineract.integrationtests.common.SchedulerJobHelper;
|
||||
@@ -62,10 +70,15 @@ import org.apache.fineract.integrationtests.common.fixeddeposit.FixedDepositProd
|
||||
import org.apache.fineract.integrationtests.common.savings.SavingsAccountHelper;
|
||||
import org.apache.fineract.integrationtests.common.savings.SavingsProductHelper;
|
||||
import org.apache.fineract.integrationtests.common.savings.SavingsStatusChecker;
|
||||
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
||||
import org.apache.fineract.portfolio.savings.data.DepositAccountDataValidator;
|
||||
import org.apache.fineract.portfolio.savings.service.FixedDepositAccountInterestCalculationServiceImpl;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
@Slf4j
|
||||
@SuppressWarnings({ "unused", "unchecked", "rawtypes", "static-access" })
|
||||
@@ -80,6 +93,8 @@ public class FixedDepositTest {
|
||||
private JournalEntryHelper journalEntryHelper;
|
||||
private FinancialActivityAccountHelper financialActivityAccountHelper;
|
||||
|
||||
private FixedDepositAccountInterestCalculationServiceImpl fixedDepositAccountInterestCalculationServiceImpl;
|
||||
|
||||
public static final String WHOLE_TERM = "1";
|
||||
public static final String TILL_PREMATURE_WITHDRAWAL = "2";
|
||||
private static final String DAILY = "1";
|
||||
@@ -114,6 +129,8 @@ public class FixedDepositTest {
|
||||
// and then to compare the exact results
|
||||
public static final Float THRESHOLD = 1.0f;
|
||||
|
||||
private MockedStatic<MoneyHelper> moneyHelperStatic;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
Utils.initializeRESTAssured();
|
||||
@@ -126,6 +143,83 @@ public class FixedDepositTest {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone(Utils.TENANT_TIME_ZONE));
|
||||
}
|
||||
|
||||
/***
|
||||
* Test case for Fixed Deposit Account Interest Calculation
|
||||
*/
|
||||
@Test
|
||||
public void testFixedDepositInterestCalculationWithWrongCompoundingPeriod() {
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("principalAmount", 100);
|
||||
jsonObject.addProperty("annualInterestRate", 5);
|
||||
jsonObject.addProperty("tenureInMonths", 12);
|
||||
jsonObject.addProperty("interestPostingPeriodInMonths", 3);
|
||||
jsonObject.addProperty("interestCompoundingPeriodInMonths", 7);
|
||||
JsonParser parser = new JsonParser();
|
||||
String apiRequestBodyAsJson = jsonObject.toString();
|
||||
JsonElement element = parser.parse(apiRequestBodyAsJson);
|
||||
moneyHelperStatic = Mockito.mockStatic(MoneyHelper.class);
|
||||
moneyHelperStatic.when(() -> MoneyHelper.getMathContext()).thenReturn(new MathContext(12, RoundingMode.UP));
|
||||
fixedDepositAccountInterestCalculationServiceImpl = new FixedDepositAccountInterestCalculationServiceImpl(
|
||||
new DepositAccountDataValidator(new FromJsonHelper(), null), new FromJsonHelper());
|
||||
try {
|
||||
HashMap h = fixedDepositAccountInterestCalculationServiceImpl
|
||||
.calculateInterest(new JsonQuery(apiRequestBodyAsJson, element, new FromJsonHelper()));
|
||||
fail("The function must throw an exception when called with invalid Compounding period");
|
||||
} catch (PlatformApiDataValidationException e) {
|
||||
assertEquals("Validation errors exist.", e.getMessage());
|
||||
} finally {
|
||||
moneyHelperStatic.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFixedDepositInterestCalculationWithWrongCompoundingPeriod2() {
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("principalAmount", 100);
|
||||
jsonObject.addProperty("annualInterestRate", 5);
|
||||
jsonObject.addProperty("tenureInMonths", 15);
|
||||
jsonObject.addProperty("interestPostingPeriodInMonths", 3);
|
||||
jsonObject.addProperty("interestCompoundingPeriodInMonths", 6);
|
||||
JsonParser parser = new JsonParser();
|
||||
String apiRequestBodyAsJson = jsonObject.toString();
|
||||
JsonElement element = parser.parse(apiRequestBodyAsJson);
|
||||
moneyHelperStatic = Mockito.mockStatic(MoneyHelper.class);
|
||||
moneyHelperStatic.when(() -> MoneyHelper.getMathContext()).thenReturn(new MathContext(12, RoundingMode.UP));
|
||||
fixedDepositAccountInterestCalculationServiceImpl = new FixedDepositAccountInterestCalculationServiceImpl(
|
||||
new DepositAccountDataValidator(new FromJsonHelper(), null), new FromJsonHelper());
|
||||
try {
|
||||
HashMap h = fixedDepositAccountInterestCalculationServiceImpl
|
||||
.calculateInterest(new JsonQuery(apiRequestBodyAsJson, element, new FromJsonHelper()));
|
||||
fail("The function must throw an exception when called with invalid Compounding period");
|
||||
} catch (PlatformApiDataValidationException e) {
|
||||
assertEquals("Validation errors exist.", e.getMessage());
|
||||
} finally {
|
||||
moneyHelperStatic.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFixedDepositInterestCalculationWithValidInput() {
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("principalAmount", 10000);
|
||||
jsonObject.addProperty("annualInterestRate", 5);
|
||||
jsonObject.addProperty("tenureInMonths", 12);
|
||||
jsonObject.addProperty("interestPostingPeriodInMonths", 3);
|
||||
jsonObject.addProperty("interestCompoundingPeriodInMonths", 6);
|
||||
JsonParser parser = new JsonParser();
|
||||
String apiRequestBodyAsJson = jsonObject.toString();
|
||||
JsonElement element = parser.parse(apiRequestBodyAsJson);
|
||||
moneyHelperStatic = Mockito.mockStatic(MoneyHelper.class);
|
||||
moneyHelperStatic.when(() -> MoneyHelper.getMathContext()).thenReturn(new MathContext(12, RoundingMode.UP));
|
||||
fixedDepositAccountInterestCalculationServiceImpl = new FixedDepositAccountInterestCalculationServiceImpl(
|
||||
new DepositAccountDataValidator(new FromJsonHelper(), null), new FromJsonHelper());
|
||||
BigDecimal expectedResult = new BigDecimal("10506.250000");
|
||||
BigDecimal actualResult = new BigDecimal(fixedDepositAccountInterestCalculationServiceImpl
|
||||
.calculateInterest(new JsonQuery(apiRequestBodyAsJson, element, new FromJsonHelper())).get("maturityAmount").toString());
|
||||
assertEquals(expectedResult, actualResult);
|
||||
moneyHelperStatic.close();
|
||||
}
|
||||
|
||||
/***
|
||||
* Test case for Fixed Deposit Product with default attributes
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user