rd account and rd product code update
This commit is contained in:
+1
-1
@@ -226,7 +226,7 @@ public class CurrentProduct extends AbstractPersistableCustom<Long> {
|
|||||||
@Column(name = "customer_segment", length = 50)
|
@Column(name = "customer_segment", length = 50)
|
||||||
private String customerSegment;
|
private String customerSegment;
|
||||||
|
|
||||||
@Column(name = "product_code", length = 20, unique = true)
|
@Column(name = "product_code", length = 20)
|
||||||
private String productCode;
|
private String productCode;
|
||||||
|
|
||||||
@Column(name = "gl_account_id")
|
@Column(name = "gl_account_id")
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
+17167
-17868
File diff suppressed because one or more lines are too long
+1
-16
@@ -102,21 +102,6 @@ public class CurrentProductsApiResource {
|
|||||||
private final CodeValueReadPlatformService codeValueReadPlatformService;
|
private final CodeValueReadPlatformService codeValueReadPlatformService;
|
||||||
private final JdbcTemplate jdbcTemplate;
|
private final JdbcTemplate jdbcTemplate;
|
||||||
|
|
||||||
private String generateNextProductCode(final String tableName, final String prefix) {
|
|
||||||
try {
|
|
||||||
String maxCode = jdbcTemplate.queryForObject(
|
|
||||||
"SELECT MAX(product_code) FROM " + tableName + " WHERE product_code LIKE ?",
|
|
||||||
String.class, prefix + "%");
|
|
||||||
if (maxCode == null || maxCode.isBlank()) {
|
|
||||||
return prefix + "001";
|
|
||||||
}
|
|
||||||
String numStr = maxCode.substring(prefix.length());
|
|
||||||
int num = Integer.parseInt(numStr);
|
|
||||||
return prefix + String.format("%03d", num + 1);
|
|
||||||
} catch (Exception e) {
|
|
||||||
return prefix + "001";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Consumes({ MediaType.APPLICATION_JSON })
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
@@ -306,7 +291,7 @@ public class CurrentProductsApiResource {
|
|||||||
interestCalculationTypeOption, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions,
|
interestCalculationTypeOption, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions,
|
||||||
periodFrequencyOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, chargeOptions,
|
periodFrequencyOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, chargeOptions,
|
||||||
penaltyOptions, taxGroupOptions, yesNoOptions, accountTypeOptions, customerSegmentOptions, accountMappingForPayment);
|
penaltyOptions, taxGroupOptions, yesNoOptions, accountTypeOptions, customerSegmentOptions, accountMappingForPayment);
|
||||||
savingsProductToReturn.setProductCode(generateNextProductCode("m_current_product", "CA-IND-"));
|
// product code removed
|
||||||
}
|
}
|
||||||
|
|
||||||
return savingsProductToReturn;
|
return savingsProductToReturn;
|
||||||
|
|||||||
+1
-16
@@ -345,7 +345,7 @@ public class FixedDepositProductsApiResource {
|
|||||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions,
|
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions,
|
||||||
paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, chargeOptions, penaltyOptions, chartTemplate,
|
paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, chargeOptions, penaltyOptions, chartTemplate,
|
||||||
preClosurePenalInterestOnTypeOptions, periodFrequencyTypeOptions, taxGroupOptions);
|
preClosurePenalInterestOnTypeOptions, periodFrequencyTypeOptions, taxGroupOptions);
|
||||||
fixedDepositProductToReturn.setProductCode(generateNextProductCode("m_savings_product", "FD-IND-"));
|
// product code removed
|
||||||
}
|
}
|
||||||
|
|
||||||
fixedDepositProductToReturn.setInterestCalculationTypeOption(interestCalculationTypeOption);
|
fixedDepositProductToReturn.setInterestCalculationTypeOption(interestCalculationTypeOption);
|
||||||
@@ -372,21 +372,6 @@ public class FixedDepositProductsApiResource {
|
|||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String generateNextProductCode(final String tableName, final String prefix) {
|
|
||||||
try {
|
|
||||||
String maxCode = jdbcTemplate.queryForObject(
|
|
||||||
"SELECT MAX(product_code) FROM " + tableName + " WHERE product_code LIKE ? AND deposit_type_enum = 200",
|
|
||||||
String.class, prefix + "%");
|
|
||||||
if (maxCode == null || maxCode.isBlank()) {
|
|
||||||
return prefix + "001";
|
|
||||||
}
|
|
||||||
String numStr = maxCode.substring(prefix.length());
|
|
||||||
int num = Integer.parseInt(numStr);
|
|
||||||
return prefix + String.format("%03d", num + 1);
|
|
||||||
} catch (Exception e) {
|
|
||||||
return prefix + "001";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@DELETE
|
@DELETE
|
||||||
@Path("{productId}")
|
@Path("{productId}")
|
||||||
|
|||||||
+15
@@ -45,6 +45,7 @@ import jakarta.ws.rs.core.UriInfo;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -77,6 +78,7 @@ import org.apache.fineract.portfolio.savings.data.SavingsAccountChargeData;
|
|||||||
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData;
|
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData;
|
||||||
import org.apache.fineract.portfolio.savings.service.DepositAccountPreMatureCalculationPlatformService;
|
import org.apache.fineract.portfolio.savings.service.DepositAccountPreMatureCalculationPlatformService;
|
||||||
import org.apache.fineract.portfolio.savings.service.DepositAccountReadPlatformService;
|
import org.apache.fineract.portfolio.savings.service.DepositAccountReadPlatformService;
|
||||||
|
import org.apache.fineract.portfolio.savings.service.RecurringDepositAccountInterestCalculationService;
|
||||||
import org.apache.fineract.portfolio.savings.service.SavingsAccountChargeReadPlatformService;
|
import org.apache.fineract.portfolio.savings.service.SavingsAccountChargeReadPlatformService;
|
||||||
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
|
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
|
||||||
import org.glassfish.jersey.media.multipart.FormDataParam;
|
import org.glassfish.jersey.media.multipart.FormDataParam;
|
||||||
@@ -99,6 +101,7 @@ public class RecurringDepositAccountsApiResource {
|
|||||||
private final DepositAccountPreMatureCalculationPlatformService accountPreMatureCalculationPlatformService;
|
private final DepositAccountPreMatureCalculationPlatformService accountPreMatureCalculationPlatformService;
|
||||||
private final BulkImportWorkbookService bulkImportWorkbookService;
|
private final BulkImportWorkbookService bulkImportWorkbookService;
|
||||||
private final BulkImportWorkbookPopulatorService bulkImportWorkbookPopulatorService;
|
private final BulkImportWorkbookPopulatorService bulkImportWorkbookPopulatorService;
|
||||||
|
private final RecurringDepositAccountInterestCalculationService recurringDepositAccountInterestCalculationService;
|
||||||
private final SqlValidator sqlValidator;
|
private final SqlValidator sqlValidator;
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@@ -369,6 +372,18 @@ public class RecurringDepositAccountsApiResource {
|
|||||||
return this.toApiJsonSerializer.serialize(result);
|
return this.toApiJsonSerializer.serialize(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("calculate-rd-interest")
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
public String calculateRecurringDepositInterest(@Context final UriInfo uriInfo, final String apiRequestBodyAsJson) {
|
||||||
|
JsonElement jsonElement = fromJsonHelper.parse(apiRequestBodyAsJson);
|
||||||
|
HashMap<String, Object> result = recurringDepositAccountInterestCalculationService
|
||||||
|
.calculateInterest(new JsonQuery(apiRequestBodyAsJson, jsonElement, fromJsonHelper));
|
||||||
|
|
||||||
|
return toApiJsonSerializer.serializeResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean is(final String commandParam, final String commandValue) {
|
private boolean is(final String commandParam, final String commandValue) {
|
||||||
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
|
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-16
@@ -333,7 +333,7 @@ public class RecurringDepositProductsApiResource {
|
|||||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions,
|
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions,
|
||||||
paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, chargeOptions, penaltyOptions, chartTemplate,
|
paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, chargeOptions, penaltyOptions, chartTemplate,
|
||||||
preClosurePenalInterestOnTypeOptions, periodFrequencyTypeOptions, taxGroupOptions);
|
preClosurePenalInterestOnTypeOptions, periodFrequencyTypeOptions, taxGroupOptions);
|
||||||
recurringDepositProductToReturn.setProductCode(generateNextProductCode("m_savings_product", "RD-IND-"));
|
// product code removed
|
||||||
}
|
}
|
||||||
|
|
||||||
recurringDepositProductToReturn.setInterestCalculationTypeOption(interestCalculationTypeOption);
|
recurringDepositProductToReturn.setInterestCalculationTypeOption(interestCalculationTypeOption);
|
||||||
@@ -360,21 +360,6 @@ public class RecurringDepositProductsApiResource {
|
|||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String generateNextProductCode(final String tableName, final String prefix) {
|
|
||||||
try {
|
|
||||||
String maxCode = jdbcTemplate.queryForObject(
|
|
||||||
"SELECT MAX(product_code) FROM " + tableName + " WHERE product_code LIKE ? AND deposit_type_enum = 300",
|
|
||||||
String.class, prefix + "%");
|
|
||||||
if (maxCode == null || maxCode.isBlank()) {
|
|
||||||
return prefix + "001";
|
|
||||||
}
|
|
||||||
String numStr = maxCode.substring(prefix.length());
|
|
||||||
int num = Integer.parseInt(numStr);
|
|
||||||
return prefix + String.format("%03d", num + 1);
|
|
||||||
} catch (Exception e) {
|
|
||||||
return prefix + "001";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── RD Interest Rate Chart endpoints ────────────────────────────────────
|
// ── RD Interest Rate Chart endpoints ────────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
+1
-16
@@ -106,21 +106,6 @@ public class SavingsProductsApiResource {
|
|||||||
private final ConfigurationDomainService configurationDomainService;
|
private final ConfigurationDomainService configurationDomainService;
|
||||||
private final JdbcTemplate jdbcTemplate;
|
private final JdbcTemplate jdbcTemplate;
|
||||||
|
|
||||||
private String generateNextProductCode(final String tableName, final String prefix) {
|
|
||||||
try {
|
|
||||||
String maxCode = jdbcTemplate.queryForObject(
|
|
||||||
"SELECT MAX(product_code) FROM " + tableName + " WHERE product_code LIKE ?",
|
|
||||||
String.class, prefix + "%");
|
|
||||||
if (maxCode == null || maxCode.isBlank()) {
|
|
||||||
return prefix + "001";
|
|
||||||
}
|
|
||||||
String numStr = maxCode.substring(prefix.length());
|
|
||||||
int num = Integer.parseInt(numStr);
|
|
||||||
return prefix + String.format("%03d", num + 1);
|
|
||||||
} catch (Exception e) {
|
|
||||||
return prefix + "001";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Consumes({ MediaType.APPLICATION_JSON })
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
@@ -315,7 +300,7 @@ public class SavingsProductsApiResource {
|
|||||||
periodFrequencyOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, chargeOptions,
|
periodFrequencyOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, chargeOptions,
|
||||||
penaltyOptions, taxGroupOptions, yesNoOptions, accountTypeOptions, customerSegmentOptions,
|
penaltyOptions, taxGroupOptions, yesNoOptions, accountTypeOptions, customerSegmentOptions,
|
||||||
accountMappingForPayment);
|
accountMappingForPayment);
|
||||||
savingsProductToReturn.setProductCode(generateNextProductCode("m_savings_product", "SB-IND-"));
|
// product code generation removed
|
||||||
}
|
}
|
||||||
|
|
||||||
return savingsProductToReturn;
|
return savingsProductToReturn;
|
||||||
|
|||||||
+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 RecurringDepositAccountInterestCalculationService {
|
||||||
|
|
||||||
|
HashMap<String, Object> calculateInterest(JsonQuery query);
|
||||||
|
}
|
||||||
+138
@@ -0,0 +1,138 @@
|
|||||||
|
/**
|
||||||
|
* 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.depositAmountParamName;
|
||||||
|
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.interestCompoundingPeriodInMonthsParamName;
|
||||||
|
import static org.apache.fineract.portfolio.savings.DepositsApiConstants.tenureInMonthsParamName;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.MathContext;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
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.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RecurringDepositAccountInterestCalculationServiceImpl implements RecurringDepositAccountInterestCalculationService {
|
||||||
|
|
||||||
|
private final FromJsonHelper fromApiJsonHelper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashMap<String, Object> calculateInterest(JsonQuery query) {
|
||||||
|
JsonElement element = query.parsedJson();
|
||||||
|
BigDecimal depositAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(depositAmountParamName, element);
|
||||||
|
BigDecimal annualInterestRate = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(annualInterestRateParamName, element);
|
||||||
|
Long tenureInMonths = this.fromApiJsonHelper.extractLongNamed(tenureInMonthsParamName, element);
|
||||||
|
Long interestCompoundingPeriodInMonths = this.fromApiJsonHelper.extractLongNamed(interestCompoundingPeriodInMonthsParamName,
|
||||||
|
element);
|
||||||
|
LocalDate submittedOnDate = this.fromApiJsonHelper.extractLocalDateNamed("submittedOnDate", element);
|
||||||
|
if (submittedOnDate == null) {
|
||||||
|
submittedOnDate = LocalDate.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal maturityAmount = this.calculateInterestInternal(depositAmount, annualInterestRate, tenureInMonths,
|
||||||
|
interestCompoundingPeriodInMonths, submittedOnDate);
|
||||||
|
|
||||||
|
BigDecimal totalPrincipal = depositAmount.multiply(BigDecimal.valueOf(tenureInMonths));
|
||||||
|
BigDecimal totalInterest = maturityAmount.subtract(totalPrincipal);
|
||||||
|
|
||||||
|
String warning = "This is an approximate calculated amount - it may vary slightly when the account is created";
|
||||||
|
|
||||||
|
HashMap<String, Object> result = new HashMap<>();
|
||||||
|
result.put("maturityAmount", maturityAmount);
|
||||||
|
result.put("totalPrincipal", totalPrincipal);
|
||||||
|
result.put("totalInterest", totalInterest);
|
||||||
|
result.put("daysInYear", 365); // Standard for this product as per image
|
||||||
|
result.put("warning", warning);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal calculateInterestInternal(BigDecimal installmentAmount, BigDecimal annualInterestRate, Long tenureInMonths,
|
||||||
|
Long interestCompoundingPeriodInMonths, LocalDate submittedOnDate) {
|
||||||
|
MathContext mc = MoneyHelper.getMathContext();
|
||||||
|
BigDecimal maturityAmount = BigDecimal.ZERO;
|
||||||
|
int totalMonths = Math.toIntExact(tenureInMonths);
|
||||||
|
|
||||||
|
if (interestCompoundingPeriodInMonths == 0) {
|
||||||
|
// Standard Banking Approach for Daily Compounding RD using Actual Calendar Days
|
||||||
|
BigDecimal currentBalance = BigDecimal.ZERO;
|
||||||
|
double dailyRate = annualInterestRate.doubleValue() / 36500.0;
|
||||||
|
LocalDate date = submittedOnDate;
|
||||||
|
|
||||||
|
for (int m = 1; m <= totalMonths; m++) {
|
||||||
|
// Add monthly installment at the start of the month
|
||||||
|
currentBalance = currentBalance.add(installmentAmount);
|
||||||
|
|
||||||
|
// Get actual days in the current month
|
||||||
|
int daysInMonth = date.lengthOfMonth();
|
||||||
|
|
||||||
|
// Calculate interest for the month using daily compounding
|
||||||
|
double multiplier = Math.pow(1.0 + dailyRate, daysInMonth);
|
||||||
|
currentBalance = currentBalance.multiply(BigDecimal.valueOf(multiplier), mc);
|
||||||
|
|
||||||
|
// Move to next month
|
||||||
|
date = date.plusMonths(1);
|
||||||
|
}
|
||||||
|
maturityAmount = currentBalance;
|
||||||
|
} else {
|
||||||
|
// Periodic Compounding (Monthly, Quarterly, etc.)
|
||||||
|
BigDecimal monthlyRate = annualInterestRate.divide(BigDecimal.valueOf(1200), mc);
|
||||||
|
BigDecimal i = monthlyRate;
|
||||||
|
int n = totalMonths;
|
||||||
|
|
||||||
|
// Standard RD formula for monthly compounding:
|
||||||
|
// M = P * ((1+i)^n - 1) / i * (1+i)
|
||||||
|
// For other periods, we can approximate or use a loop.
|
||||||
|
// Using loop for consistency with various compounding periods.
|
||||||
|
BigDecimal compoundingFrequencyMonths = BigDecimal.valueOf(interestCompoundingPeriodInMonths);
|
||||||
|
BigDecimal ratePerCompounding = annualInterestRate.divide(BigDecimal.valueOf(100), mc)
|
||||||
|
.multiply(compoundingFrequencyMonths).divide(BigDecimal.valueOf(12), mc);
|
||||||
|
|
||||||
|
for (int m = 1; m <= totalMonths; m++) {
|
||||||
|
BigDecimal monthsRemaining = BigDecimal.valueOf(totalMonths - m + 1);
|
||||||
|
BigDecimal numberOfCompoundings = monthsRemaining.divide(compoundingFrequencyMonths, mc);
|
||||||
|
|
||||||
|
BigDecimal installmentMaturity = installmentAmount.multiply(
|
||||||
|
BigDecimal.ONE.add(ratePerCompounding).pow(numberOfCompoundings.intValue(), mc), mc);
|
||||||
|
|
||||||
|
// Add remaining partial compounding period interest (simple interest for the rest)
|
||||||
|
BigDecimal remainingMonths = monthsRemaining.remainder(compoundingFrequencyMonths);
|
||||||
|
if (remainingMonths.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal partialInterest = installmentMaturity.multiply(annualInterestRate).multiply(remainingMonths)
|
||||||
|
.divide(BigDecimal.valueOf(1200), mc);
|
||||||
|
installmentMaturity = installmentMaturity.add(partialInterest);
|
||||||
|
}
|
||||||
|
|
||||||
|
maturityAmount = maturityAmount.add(installmentMaturity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maturityAmount.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -288,5 +288,6 @@
|
|||||||
<include file="parts/0278_add_is_mandatory_to_joint_holder.xml" relativeToChangelogFile="true"/>
|
<include file="parts/0278_add_is_mandatory_to_joint_holder.xml" relativeToChangelogFile="true"/>
|
||||||
<include file="parts/0279_add_fd_type_and_base_interest_rate_tables.xml" relativeToChangelogFile="true"/>
|
<include file="parts/0279_add_fd_type_and_base_interest_rate_tables.xml" relativeToChangelogFile="true"/>
|
||||||
<include file="parts/0280_add_fixed_deposit_product_codes.xml" relativeToChangelogFile="true"/>
|
<include file="parts/0280_add_fixed_deposit_product_codes.xml" relativeToChangelogFile="true"/>
|
||||||
|
<include file="parts/0284_remove_product_code_unique_constraints.xml" relativeToChangelogFile="true"/>
|
||||||
<include file="parts/0281_update_fd_base_interest_rate_seed_data.xml" relativeToChangelogFile="true"/>
|
<include file="parts/0281_update_fd_base_interest_rate_seed_data.xml" relativeToChangelogFile="true"/>
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
|
|||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||||
|
|
||||||
|
<changeSet id="0284_remove_product_code_unique_constraints" author="system">
|
||||||
|
<!-- For Savings/RD/FD products -->
|
||||||
|
<dropUniqueConstraint tableName="m_savings_product" constraintName="m_savings_product_product_code_key"/>
|
||||||
|
|
||||||
|
<!-- For Current products -->
|
||||||
|
<dropUniqueConstraint tableName="m_current_product" constraintName="cp_unq_product_code"/>
|
||||||
|
|
||||||
|
<!-- Set existing empty or blank product_codes to NULL to avoid future issues -->
|
||||||
|
<update tableName="m_savings_product">
|
||||||
|
<column name="product_code" valueComputed="NULL"/>
|
||||||
|
<where>product_code = '' OR product_code IS NULL</where>
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<update tableName="m_current_product">
|
||||||
|
<column name="product_code" valueComputed="NULL"/>
|
||||||
|
<where>product_code = '' OR product_code IS NULL</where>
|
||||||
|
</update>
|
||||||
|
</changeSet>
|
||||||
|
|
||||||
|
</databaseChangeLog>
|
||||||
+1
-1
@@ -246,7 +246,7 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
|
|||||||
@Column(name = "customer_segment", length = 50)
|
@Column(name = "customer_segment", length = 50)
|
||||||
private String customerSegment;
|
private String customerSegment;
|
||||||
|
|
||||||
@Column(name = "product_code", length = 20, unique = true)
|
@Column(name = "product_code", length = 20)
|
||||||
private String productCode;
|
private String productCode;
|
||||||
|
|
||||||
@Column(name = "gl_account_id")
|
@Column(name = "gl_account_id")
|
||||||
|
|||||||
Reference in New Issue
Block a user