fd product releated update code
This commit is contained in:
+98
@@ -274,6 +274,46 @@ public final class DepositsApiConstants {
|
||||
fixedDepositRequestData.addAll(DEPOSIT_PRODUCT_REQUEST_DATA_PARAMETERS);
|
||||
fixedDepositRequestData.addAll(PRECLOSURE_REQUEST_DATA_PARAMETERS);
|
||||
fixedDepositRequestData.addAll(DEPOSIT_TERM_REQUEST_DATA_PARAMETERS);
|
||||
fixedDepositRequestData.add(SavingsApiConstants.minBalanceForInterestCalculationParamName);
|
||||
fixedDepositRequestData.add("accountType");
|
||||
fixedDepositRequestData.add("customerSegment");
|
||||
fixedDepositRequestData.add("productCode");
|
||||
fixedDepositRequestData.add("fdType");
|
||||
fixedDepositRequestData.add(SavingsApiConstants.glAccountIdParamName);
|
||||
fixedDepositRequestData.add("effectiveDate");
|
||||
fixedDepositRequestData.add("effectiveTo");
|
||||
fixedDepositRequestData.add("endDate");
|
||||
fixedDepositRequestData.add("introducerRequired");
|
||||
fixedDepositRequestData.add("shareLinkingEnabled");
|
||||
fixedDepositRequestData.add("nominationFacility");
|
||||
fixedDepositRequestData.add("dormancyAlert");
|
||||
fixedDepositRequestData.add(SavingsApiConstants.isDormancyTrackingActiveParamName);
|
||||
fixedDepositRequestData.add(SavingsApiConstants.daysToInactiveParamName);
|
||||
fixedDepositRequestData.add(SavingsApiConstants.daysToDormancyParamName);
|
||||
fixedDepositRequestData.add(SavingsApiConstants.daysToEscheatParamName);
|
||||
fixedDepositRequestData.add("interestCalculateSelector");
|
||||
fixedDepositRequestData.add("averagePeriod");
|
||||
fixedDepositRequestData.add("autoPost");
|
||||
fixedDepositRequestData.add("frequencyFixDay");
|
||||
fixedDepositRequestData.add("lastInterestDate");
|
||||
fixedDepositRequestData.add("enableLockinPeriod");
|
||||
fixedDepositRequestData.add("balanceFrequency");
|
||||
fixedDepositRequestData.add("accountClosedZeroBalanceInDayClosing");
|
||||
fixedDepositRequestData.add("autoDebitFacility");
|
||||
fixedDepositRequestData.add("loanFacility");
|
||||
fixedDepositRequestData.add("prematureWithdrawalOption");
|
||||
fixedDepositRequestData.add("tenureFlexibility");
|
||||
fixedDepositRequestData.add("lienMarked");
|
||||
fixedDepositRequestData.add("withdrawalFeeForTransfers");
|
||||
fixedDepositRequestData.add("maturityInstructions");
|
||||
fixedDepositRequestData.add("creditMaturityProceeds");
|
||||
fixedDepositRequestData.add("penaltyGracePeriodMissedInstallments");
|
||||
fixedDepositRequestData.add("panelRequestApplicable");
|
||||
fixedDepositRequestData.add("noPenaltyNomineeHeirClosure");
|
||||
fixedDepositRequestData.add("deceasedSettlement");
|
||||
fixedDepositRequestData.add("allowDebitTxnAfterDueDate");
|
||||
fixedDepositRequestData.add("escheatLiabilityId");
|
||||
fixedDepositRequestData.add("fdSlabs");
|
||||
return fixedDepositRequestData;
|
||||
}
|
||||
|
||||
@@ -282,6 +322,54 @@ public final class DepositsApiConstants {
|
||||
fixedDepositRequestData.addAll(DEPOSIT_PRODUCT_REQUEST_DATA_PARAMETERS);
|
||||
fixedDepositRequestData.addAll(PRECLOSURE_RESPONSE_DATA_PARAMETERS);
|
||||
fixedDepositRequestData.addAll(DEPOSIT_TERM_RESPONSE_DATA_PARAMETERS);
|
||||
fixedDepositRequestData.add(SavingsApiConstants.minBalanceForInterestCalculationParamName);
|
||||
fixedDepositRequestData.add("interestCalculationTypeOption");
|
||||
fixedDepositRequestData.add("periodFrequencyOptions");
|
||||
fixedDepositRequestData.add("yesNoOptions");
|
||||
fixedDepositRequestData.add("accountTypeOptions");
|
||||
fixedDepositRequestData.add("customerSegmentOptions");
|
||||
fixedDepositRequestData.add("accountType");
|
||||
fixedDepositRequestData.add("customerSegment");
|
||||
fixedDepositRequestData.add("productCode");
|
||||
fixedDepositRequestData.add("fdType");
|
||||
fixedDepositRequestData.add(SavingsApiConstants.glAccountIdParamName);
|
||||
fixedDepositRequestData.add("glAccountName");
|
||||
fixedDepositRequestData.add("effectiveDate");
|
||||
fixedDepositRequestData.add("effectiveTo");
|
||||
fixedDepositRequestData.add("endDate");
|
||||
fixedDepositRequestData.add("introducerRequired");
|
||||
fixedDepositRequestData.add("shareLinkingEnabled");
|
||||
fixedDepositRequestData.add("nominationFacility");
|
||||
fixedDepositRequestData.add("dormancyAlert");
|
||||
fixedDepositRequestData.add(SavingsApiConstants.isDormancyTrackingActiveParamName);
|
||||
fixedDepositRequestData.add(SavingsApiConstants.daysToInactiveParamName);
|
||||
fixedDepositRequestData.add(SavingsApiConstants.daysToDormancyParamName);
|
||||
fixedDepositRequestData.add(SavingsApiConstants.daysToEscheatParamName);
|
||||
fixedDepositRequestData.add("interestCalculateSelector");
|
||||
fixedDepositRequestData.add("averagePeriod");
|
||||
fixedDepositRequestData.add("autoPost");
|
||||
fixedDepositRequestData.add("frequencyFixDay");
|
||||
fixedDepositRequestData.add("lastInterestDate");
|
||||
fixedDepositRequestData.add("enableLockinPeriod");
|
||||
fixedDepositRequestData.add("balanceFrequency");
|
||||
fixedDepositRequestData.add("accountClosedZeroBalanceInDayClosing");
|
||||
fixedDepositRequestData.add("autoDebitFacility");
|
||||
fixedDepositRequestData.add("loanFacility");
|
||||
fixedDepositRequestData.add("prematureWithdrawalOption");
|
||||
fixedDepositRequestData.add("tenureFlexibility");
|
||||
fixedDepositRequestData.add("lienMarked");
|
||||
fixedDepositRequestData.add("withdrawalFeeForTransfers");
|
||||
fixedDepositRequestData.add("maturityInstructions");
|
||||
fixedDepositRequestData.add("creditMaturityProceeds");
|
||||
fixedDepositRequestData.add("penaltyGracePeriodMissedInstallments");
|
||||
fixedDepositRequestData.add("panelRequestApplicable");
|
||||
fixedDepositRequestData.add("noPenaltyNomineeHeirClosure");
|
||||
fixedDepositRequestData.add("deceasedSettlement");
|
||||
fixedDepositRequestData.add("allowDebitTxnAfterDueDate");
|
||||
fixedDepositRequestData.add("accountingMappings");
|
||||
fixedDepositRequestData.add("paymentChannelToFundSourceMappings");
|
||||
fixedDepositRequestData.add("feeToIncomeAccountMappings");
|
||||
fixedDepositRequestData.add("penaltyToIncomeAccountMappings");
|
||||
return fixedDepositRequestData;
|
||||
}
|
||||
|
||||
@@ -332,6 +420,7 @@ public final class DepositsApiConstants {
|
||||
recurringDepositRequestData.add("deceasedSettlement");
|
||||
recurringDepositRequestData.add("allowDebitTxnAfterDueDate");
|
||||
recurringDepositRequestData.add("accountClosedZeroBalanceInDayClosing");
|
||||
recurringDepositRequestData.add("escheatLiabilityId");
|
||||
// Custom CBS fields — Interest rate slabs (sent inline but ignored server-side; saved separately)
|
||||
recurringDepositRequestData.add("rdSlabs");
|
||||
return recurringDepositRequestData;
|
||||
@@ -387,6 +476,11 @@ public final class DepositsApiConstants {
|
||||
recurringDepositRequestData.add("noPenaltyNomineeHeirClosure");
|
||||
recurringDepositRequestData.add("deceasedSettlement");
|
||||
recurringDepositRequestData.add("allowDebitTxnAfterDueDate");
|
||||
recurringDepositRequestData.add("escheatLiabilityId");
|
||||
recurringDepositRequestData.add("accountingMappings");
|
||||
recurringDepositRequestData.add("paymentChannelToFundSourceMappings");
|
||||
recurringDepositRequestData.add("feeToIncomeAccountMappings");
|
||||
recurringDepositRequestData.add("penaltyToIncomeAccountMappings");
|
||||
return recurringDepositRequestData;
|
||||
}
|
||||
|
||||
@@ -517,6 +611,10 @@ public final class DepositsApiConstants {
|
||||
recurringDepositResponseData.add("noPenaltyNomineeHeirClosure");
|
||||
recurringDepositResponseData.add("deceasedSettlement");
|
||||
recurringDepositResponseData.add("allowDebitTxnAfterDueDate");
|
||||
recurringDepositResponseData.add("accountingMappings");
|
||||
recurringDepositResponseData.add("paymentChannelToFundSourceMappings");
|
||||
recurringDepositResponseData.add("feeToIncomeAccountMappings");
|
||||
recurringDepositResponseData.add("penaltyToIncomeAccountMappings");
|
||||
return recurringDepositResponseData;
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -32,6 +32,8 @@ public class SavingsApiConstants {
|
||||
public static final String CURRENT_PRODUCT_CUSTOMER_SEGMENT = "CurrentProductCustomerSegment";
|
||||
public static final String RD_PRODUCT_ACCOUNT_TYPE = "RecurringDepositProductAccountType";
|
||||
public static final String RD_PRODUCT_CUSTOMER_SEGMENT = "RecurringDepositProductCustomerSegment";
|
||||
public static final String FD_PRODUCT_ACCOUNT_TYPE = "FixedDepositProductAccountType";
|
||||
public static final String FD_PRODUCT_CUSTOMER_SEGMENT = "FixedDepositProductCustomerSegment";
|
||||
public static final String PERIOD_FREQUENCY = "PeriodFrequency";
|
||||
public static final String INTEREST_CALCULATION_TYPE_OPTION = "InterestCalculationTypeOption";
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+18035
-15465
File diff suppressed because it is too large
Load Diff
+42
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.api;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class FdInterestRateSaveRequest {
|
||||
|
||||
private String fdType;
|
||||
private String versionLabel;
|
||||
private String remarks;
|
||||
private List<SlabRequest> slabs;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public static class SlabRequest {
|
||||
private Integer srNo;
|
||||
private String description;
|
||||
private Integer periodTypeEnum;
|
||||
private Integer fromPeriod;
|
||||
private Integer toPeriod;
|
||||
private BigDecimal annualInterestRate;
|
||||
private BigDecimal seniorCitizenRate;
|
||||
}
|
||||
}
|
||||
+54
@@ -54,9 +54,13 @@ import org.apache.fineract.commands.service.CommandWrapperBuilder;
|
||||
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import java.util.Locale;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
|
||||
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
|
||||
import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.organisation.monetary.service.CurrencyReadPlatformService;
|
||||
@@ -110,6 +114,8 @@ public class FixedDepositProductsApiResource {
|
||||
private final DropdownReadPlatformService dropdownReadPlatformService;
|
||||
private final PaymentTypeReadService paymentTypeReadPlatformService;
|
||||
private final TaxReadPlatformService taxReadPlatformService;
|
||||
private final CodeValueReadPlatformService codeValueReadPlatformService;
|
||||
private final org.springframework.jdbc.core.JdbcTemplate jdbcTemplate;
|
||||
|
||||
@POST
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@@ -315,6 +321,16 @@ public class FixedDepositProductsApiResource {
|
||||
// interest rate chart template
|
||||
final InterestRateChartData chartTemplate = this.interestRateChartReadPlatformService.template();
|
||||
|
||||
// CBS custom options
|
||||
final Collection<EnumOptionData> interestCalculationTypeOption = retrieveInterestCalculationTypeOption();
|
||||
final Collection<EnumOptionData> periodFrequencyOptions = retrievePeriodFrequencyOptions();
|
||||
final List<CodeValueData> yesNoOptions = new ArrayList<>(
|
||||
this.codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.YES_NO));
|
||||
final List<CodeValueData> accountTypeOptions = new ArrayList<>(
|
||||
this.codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.FD_PRODUCT_ACCOUNT_TYPE));
|
||||
final List<CodeValueData> customerSegmentOptions = new ArrayList<>(
|
||||
this.codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.FD_PRODUCT_CUSTOMER_SEGMENT));
|
||||
|
||||
FixedDepositProductData fixedDepositProductToReturn = null;
|
||||
if (savingsProduct != null) {
|
||||
fixedDepositProductToReturn = FixedDepositProductData.withTemplate(savingsProduct, currencyOptions,
|
||||
@@ -329,11 +345,49 @@ public class FixedDepositProductsApiResource {
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions,
|
||||
paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, chargeOptions, penaltyOptions, chartTemplate,
|
||||
preClosurePenalInterestOnTypeOptions, periodFrequencyTypeOptions, taxGroupOptions);
|
||||
fixedDepositProductToReturn.setProductCode(generateNextProductCode("m_savings_product", "FD-IND-"));
|
||||
}
|
||||
|
||||
fixedDepositProductToReturn.setInterestCalculationTypeOption(interestCalculationTypeOption);
|
||||
fixedDepositProductToReturn.setPeriodFrequencyOptions(periodFrequencyOptions);
|
||||
fixedDepositProductToReturn.setYesNoOptions(yesNoOptions);
|
||||
fixedDepositProductToReturn.setAccountTypeOptions(accountTypeOptions);
|
||||
fixedDepositProductToReturn.setCustomerSegmentOptions(customerSegmentOptions);
|
||||
|
||||
return fixedDepositProductToReturn;
|
||||
}
|
||||
|
||||
private Collection<EnumOptionData> retrievePeriodFrequencyOptions() {
|
||||
return this.codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.PERIOD_FREQUENCY).stream()
|
||||
.map(codeValue -> new EnumOptionData(codeValue.getId(),
|
||||
"periodFrequencyType." + codeValue.getName().toLowerCase(Locale.ROOT).replace(' ', '_'), codeValue.getName()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private Collection<EnumOptionData> retrieveInterestCalculationTypeOption() {
|
||||
return this.codeValueReadPlatformService.retrieveCodeValuesByCode(SavingsApiConstants.INTEREST_CALCULATION_TYPE_OPTION).stream()
|
||||
.map(codeValue -> new EnumOptionData(codeValue.getId(),
|
||||
"interestCalculationTypeOption." + codeValue.getName().toLowerCase(Locale.ROOT).replace(' ', '_'),
|
||||
codeValue.getName()))
|
||||
.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
|
||||
@Path("{productId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
|
||||
+1
@@ -342,6 +342,7 @@ final class FixedDepositProductsApiResourceSwagger {
|
||||
public GetFixedDepositProductsGlAccount interestOnSavingsAccount;
|
||||
public GetFixedDepositProductsGlAccount savingsControlAccount;
|
||||
public GetFixedDepositProductsGlAccount transfersInSuspenseAccount;
|
||||
public GetFixedDepositProductsGlAccount escheatLiabilityAccount;
|
||||
public GetFixedDepositProductsGlAccount interestPayableAccount;
|
||||
}
|
||||
|
||||
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.api;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.apache.fineract.portfolio.savings.DepositsApiConstants;
|
||||
import org.apache.fineract.portfolio.savings.data.FdInterestRateEffectiveData;
|
||||
import org.apache.fineract.portfolio.savings.service.FdBaseInterestRateReadPlatformService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/v1/fixeddepositproducts/baseinterestrates")
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class FixedDepositProductsBaseInterestRatesApiResource {
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final FdBaseInterestRateReadPlatformService fdBaseInterestRateReadPlatformService;
|
||||
private final Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(LocalDate.class,
|
||||
(JsonSerializer<LocalDate>) (src, typeOfSrc, ctx) -> new JsonPrimitive(src.toString()))
|
||||
.create();
|
||||
|
||||
@GET
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(summary = "Get all active FD base interest rate charts", description = "Returns active CBS FD base interest-rate versions with slabs. Optionally filter by fdType (SINGLE, DOUBLE, SPECIAL).")
|
||||
@ApiResponses({ @ApiResponse(responseCode = "200", description = "OK") })
|
||||
public String retrieveAllActiveInterestRates(@QueryParam("fdType") final String fdType) {
|
||||
this.context.authenticatedUser().validateHasReadPermission(DepositsApiConstants.FIXED_DEPOSIT_PRODUCT_RESOURCE_NAME);
|
||||
final List<FdInterestRateEffectiveData> data = fdType != null && !fdType.isBlank()
|
||||
? this.fdBaseInterestRateReadPlatformService.retrieveActiveInterestRatesByType(fdType)
|
||||
: this.fdBaseInterestRateReadPlatformService.retrieveAllActiveInterestRates();
|
||||
return gson.toJson(data);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("history")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(summary = "Get all FD base interest rate charts", description = "Returns the full FD base chart history.")
|
||||
@ApiResponses({ @ApiResponse(responseCode = "200", description = "OK") })
|
||||
public String retrieveHistory() {
|
||||
this.context.authenticatedUser().validateHasReadPermission(DepositsApiConstants.FIXED_DEPOSIT_PRODUCT_RESOURCE_NAME);
|
||||
final List<FdInterestRateEffectiveData> data = this.fdBaseInterestRateReadPlatformService.retrieveAllInterestRates();
|
||||
return gson.toJson(data);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(summary = "Save new FD base interest rate version", description = "Creates a new FD CBS base chart version for the given fdType and deactivates the previous active version.")
|
||||
@ApiResponses({ @ApiResponse(responseCode = "200", description = "OK") })
|
||||
public String saveInterestRates(@Parameter(hidden = true) final String apiRequestBodyAsJson) {
|
||||
this.context.authenticatedUser().validateHasReadPermission(DepositsApiConstants.FIXED_DEPOSIT_PRODUCT_RESOURCE_NAME);
|
||||
final FdInterestRateSaveRequest request = gson.fromJson(apiRequestBodyAsJson, FdInterestRateSaveRequest.class);
|
||||
final Long createdById = this.context.authenticatedUser().getId();
|
||||
final FdInterestRateEffectiveData saved = this.fdBaseInterestRateReadPlatformService.saveInterestRates(request, createdById);
|
||||
return gson.toJson(saved);
|
||||
}
|
||||
}
|
||||
+1
@@ -360,6 +360,7 @@ final class RecurringDepositProductsApiResourceSwagger {
|
||||
public GetRecurringDepositProductsGlAccount interestOnSavingsAccount;
|
||||
public GetRecurringDepositProductsGlAccount savingsControlAccount;
|
||||
public GetRecurringDepositProductsGlAccount transfersInSuspenseAccount;
|
||||
public GetRecurringDepositProductsGlAccount escheatLiabilityAccount;
|
||||
public GetRecurringDepositProductsGlAccount feeReceivableAccount;
|
||||
public GetRecurringDepositProductsGlAccount penaltyReceivableAccount;
|
||||
public GetRecurringDepositProductsGlAccount interestPayableAccount;
|
||||
|
||||
+1
@@ -285,6 +285,7 @@ final class SavingsProductsApiResourceSwagger {
|
||||
public GetSavingsProductsGlAccount writeOffAccount;
|
||||
public GetSavingsProductsGlAccount savingsControlAccount;
|
||||
public GetSavingsProductsGlAccount transfersInSuspenseAccount;
|
||||
public GetSavingsProductsGlAccount escheatLiabilityAccount;
|
||||
public GetSavingsProductsGlAccount interestPayableAccount;
|
||||
}
|
||||
|
||||
|
||||
+7
-3
@@ -632,8 +632,12 @@ public class DepositProductDataValidator {
|
||||
}
|
||||
|
||||
private void validateDepositAmountForCreate(JsonElement element, DataValidatorBuilder baseDataValidator) {
|
||||
final BigDecimal depositAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(depositAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(depositAmountParamName).value(depositAmount).notNull().positiveAmount();
|
||||
final BigDecimal depositAmount = this.fromApiJsonHelper.parameterExists(depositAmountParamName, element)
|
||||
? this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(depositAmountParamName, element)
|
||||
: null;
|
||||
if (depositAmount != null) {
|
||||
baseDataValidator.reset().parameter(depositAmountParamName).value(depositAmount).positiveAmount();
|
||||
}
|
||||
|
||||
BigDecimal depositMinAmount = null;
|
||||
if (this.fromApiJsonHelper.parameterExists(depositMinAmountParamName, element)) {
|
||||
@@ -667,7 +671,7 @@ public class DepositProductDataValidator {
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(depositAmountParamName, element)) {
|
||||
depositAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(depositAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(depositAmountParamName).value(depositAmount).notNull().positiveAmount();
|
||||
baseDataValidator.reset().parameter(depositAmountParamName).value(depositAmount).positiveAmount();
|
||||
}
|
||||
|
||||
BigDecimal depositMinAmount = null;
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.data;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class FdInterestRateEffectiveData {
|
||||
|
||||
private Long id;
|
||||
private String fdType;
|
||||
private String versionLabel;
|
||||
private LocalDate effectiveFromDate;
|
||||
private LocalDate effectiveToDate;
|
||||
private Boolean isActive;
|
||||
private String remarks;
|
||||
private List<FdInterestRateSlabData> slabs;
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class FdInterestRateSlabData {
|
||||
|
||||
private Long id;
|
||||
private Integer srNo;
|
||||
private String description;
|
||||
private Integer periodTypeEnum;
|
||||
private String periodTypeLabel;
|
||||
private Integer fromPeriod;
|
||||
private Integer toPeriod;
|
||||
private BigDecimal annualInterestRate;
|
||||
private BigDecimal seniorCitizenRate;
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.LocalDate;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_fd_base_interest_rate_effective")
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class FdBaseInterestRateEffective {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "fd_type", length = 20)
|
||||
private String fdType;
|
||||
|
||||
@Column(name = "version_label")
|
||||
private String versionLabel;
|
||||
|
||||
@Column(name = "effective_from_date")
|
||||
private LocalDate effectiveFromDate;
|
||||
|
||||
@Column(name = "effective_to_date")
|
||||
private LocalDate effectiveToDate;
|
||||
|
||||
@Column(name = "is_active")
|
||||
private Boolean isActive;
|
||||
|
||||
@Column(name = "remarks")
|
||||
private String remarks;
|
||||
|
||||
@Column(name = "created_by_id")
|
||||
private Long createdById;
|
||||
|
||||
@Column(name = "created_date")
|
||||
private LocalDate createdDate;
|
||||
|
||||
public static FdBaseInterestRateEffective create(String fdType, String versionLabel, LocalDate effectiveFromDate, String remarks,
|
||||
Long createdById) {
|
||||
FdBaseInterestRateEffective e = new FdBaseInterestRateEffective();
|
||||
e.fdType = fdType;
|
||||
e.versionLabel = versionLabel;
|
||||
e.effectiveFromDate = effectiveFromDate;
|
||||
e.isActive = true;
|
||||
e.remarks = remarks;
|
||||
e.createdById = createdById;
|
||||
e.createdDate = LocalDate.now();
|
||||
return e;
|
||||
}
|
||||
|
||||
public void deactivate(LocalDate toDate) {
|
||||
this.isActive = false;
|
||||
this.effectiveToDate = toDate;
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface FdBaseInterestRateEffectiveRepository extends JpaRepository<FdBaseInterestRateEffective, Long> {
|
||||
|
||||
List<FdBaseInterestRateEffective> findByFdTypeAndIsActiveTrueOrderByEffectiveFromDateDesc(String fdType);
|
||||
|
||||
List<FdBaseInterestRateEffective> findByFdTypeOrderByEffectiveFromDateDesc(String fdType);
|
||||
|
||||
List<FdBaseInterestRateEffective> findByIsActiveTrueOrderByEffectiveFromDateDesc();
|
||||
|
||||
List<FdBaseInterestRateEffective> findByOrderByEffectiveFromDateDesc();
|
||||
}
|
||||
+76
@@ -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
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_fd_base_interest_rate_slab_history")
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class FdBaseInterestRateSlabHistory {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "effective_id")
|
||||
private Long effectiveId;
|
||||
|
||||
@Column(name = "sr_no")
|
||||
private Integer srNo;
|
||||
|
||||
@Column(name = "description")
|
||||
private String description;
|
||||
|
||||
@Column(name = "period_type_enum")
|
||||
private Integer periodTypeEnum;
|
||||
|
||||
@Column(name = "from_period")
|
||||
private Integer fromPeriod;
|
||||
|
||||
@Column(name = "to_period")
|
||||
private Integer toPeriod;
|
||||
|
||||
@Column(name = "annual_interest_rate")
|
||||
private BigDecimal annualInterestRate;
|
||||
|
||||
@Column(name = "senior_citizen_rate")
|
||||
private BigDecimal seniorCitizenRate;
|
||||
|
||||
@Column(name = "created_date")
|
||||
private LocalDate createdDate;
|
||||
|
||||
public static FdBaseInterestRateSlabHistory create(Long effectiveId, Integer srNo, String description, Integer periodTypeEnum,
|
||||
Integer fromPeriod, Integer toPeriod, BigDecimal annualInterestRate, BigDecimal seniorCitizenRate) {
|
||||
FdBaseInterestRateSlabHistory s = new FdBaseInterestRateSlabHistory();
|
||||
s.effectiveId = effectiveId;
|
||||
s.srNo = srNo;
|
||||
s.description = description;
|
||||
s.periodTypeEnum = periodTypeEnum != null ? periodTypeEnum : 1;
|
||||
s.fromPeriod = fromPeriod;
|
||||
s.toPeriod = toPeriod;
|
||||
s.annualInterestRate = annualInterestRate;
|
||||
s.seniorCitizenRate = seniorCitizenRate;
|
||||
s.createdDate = LocalDate.now();
|
||||
return s;
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface FdBaseInterestRateSlabHistoryRepository extends JpaRepository<FdBaseInterestRateSlabHistory, Long> {
|
||||
|
||||
List<FdBaseInterestRateSlabHistory> findByEffectiveIdOrderBySrNo(Long effectiveId);
|
||||
}
|
||||
+77
-5
@@ -230,11 +230,37 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead
|
||||
sqlBuilder.append("dptp.in_multiples_of_deposit_term as inMultiplesOfDepositTerm, ");
|
||||
sqlBuilder.append("dptp.in_multiples_of_deposit_term_type_enum as inMultiplesOfDepositTermTypeId, ");
|
||||
sqlBuilder.append("dptp.min_deposit_amount as minDepositAmount, dptp.deposit_amount as depositAmount, ");
|
||||
sqlBuilder.append("dptp.max_deposit_amount as maxDepositAmount ");
|
||||
sqlBuilder.append("dptp.max_deposit_amount as maxDepositAmount, ");
|
||||
sqlBuilder.append("sp.account_type as accountType, sp.fd_type as fdType, sp.product_code as productCode, ");
|
||||
sqlBuilder.append("sp.customer_segment as customerSegment, ");
|
||||
sqlBuilder.append("sp.gl_account_id as glAccountId, gla.name as glAccountName, ");
|
||||
sqlBuilder.append("sp.effective_date as effectiveDate, sp.effective_to as effectiveTo, sp.end_date as endDate, ");
|
||||
sqlBuilder.append("sp.introducer_required as introducerRequired, sp.share_linking_enabled as shareLinkingEnabled, ");
|
||||
sqlBuilder.append("sp.nomination_facility as nominationFacility, sp.dormancy_alert as dormancyAlert, ");
|
||||
sqlBuilder.append("sp.is_dormancy_tracking_active as isDormancyTrackingActive, ");
|
||||
sqlBuilder.append("sp.days_to_inactive as daysToInactive, sp.days_to_dormancy as daysToDormancy, ");
|
||||
sqlBuilder.append("sp.days_to_escheat as daysToEscheat, ");
|
||||
sqlBuilder.append("sp.interest_calculate_selector as interestCalculateSelector, ");
|
||||
sqlBuilder.append("sp.average_period as averagePeriod, ");
|
||||
sqlBuilder.append("sp.auto_post as autoPost, sp.frequency_fix_day as frequencyFixDay, ");
|
||||
sqlBuilder.append("sp.last_interest_date as lastInterestDate, sp.enable_lockin_period as enableLockinPeriod, ");
|
||||
sqlBuilder.append("sp.balance_frequency as balanceFrequency, ");
|
||||
sqlBuilder.append("sp.account_closed_zero_balance_in_day_closing as accountClosedZeroBalanceInDayClosing, ");
|
||||
sqlBuilder.append("sp.auto_debit_facility as autoDebitFacility, sp.loan_facility as loanFacility, ");
|
||||
sqlBuilder.append("sp.premature_withdrawal_option as prematureWithdrawalOption, sp.tenure_flexibility as tenureFlexibility, ");
|
||||
sqlBuilder.append("sp.lien_marked as lienMarked, sp.maturity_instructions as maturityInstructions, ");
|
||||
sqlBuilder.append("sp.credit_maturity_proceeds as creditMaturityProceeds, ");
|
||||
sqlBuilder.append("sp.penalty_grace_period_missed_installments as penaltyGracePeriodMissedInstallments, ");
|
||||
sqlBuilder.append("sp.panel_request_applicable as panelRequestApplicable, ");
|
||||
sqlBuilder.append("sp.no_penalty_nominee_heir_closure as noPenaltyNomineeHeirClosure, ");
|
||||
sqlBuilder.append("sp.deceased_settlement as deceasedSettlement, ");
|
||||
sqlBuilder.append("sp.allow_debit_txn_after_due_date as allowDebitTxnAfterDueDate, ");
|
||||
sqlBuilder.append("sp.withdrawal_fee_for_transfer as withdrawalFeeForTransfers ");
|
||||
sqlBuilder.append("from m_savings_product sp ");
|
||||
sqlBuilder.append("left join m_deposit_product_term_and_preclosure dptp on sp.id=dptp.savings_product_id ");
|
||||
sqlBuilder.append("join m_currency curr on curr.code = sp.currency_code ");
|
||||
sqlBuilder.append(" left join m_tax_group tg on tg.id = sp.tax_group_id ");
|
||||
sqlBuilder.append("left join m_tax_group tg on tg.id = sp.tax_group_id ");
|
||||
sqlBuilder.append("left join acc_gl_account gla on gla.id = sp.gl_account_id ");
|
||||
|
||||
this.schemaSql = sqlBuilder.toString();
|
||||
}
|
||||
@@ -271,9 +297,55 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead
|
||||
final BigDecimal depositAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "depositAmount");
|
||||
final BigDecimal maxDepositAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "maxDepositAmount");
|
||||
|
||||
return FixedDepositProductData.instance(depositProductData, preClosurePenalApplicable, preClosurePenalInterest,
|
||||
preClosurePenalInterestOnType, minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType,
|
||||
inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, minDepositAmount, depositAmount, maxDepositAmount);
|
||||
final FixedDepositProductData result = FixedDepositProductData.instance(depositProductData, preClosurePenalApplicable,
|
||||
preClosurePenalInterest, preClosurePenalInterestOnType, minDepositTerm, maxDepositTerm, minDepositTermType,
|
||||
maxDepositTermType, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, minDepositAmount, depositAmount,
|
||||
maxDepositAmount);
|
||||
|
||||
// CBS Custom Fields
|
||||
result.setAccountType(rs.getString("accountType"));
|
||||
result.setFdType(rs.getString("fdType"));
|
||||
result.setProductCode(rs.getString("productCode"));
|
||||
result.setCustomerSegment(rs.getString("customerSegment"));
|
||||
result.setGlAccountId(JdbcSupport.getLong(rs, "glAccountId"));
|
||||
result.setGlAccountName(rs.getString("glAccountName"));
|
||||
final java.time.LocalDate effectiveDate = JdbcSupport.getLocalDate(rs, "effectiveDate");
|
||||
result.setEffectiveDate(effectiveDate != null ? effectiveDate.toString() : null);
|
||||
final java.time.LocalDate effectiveTo = JdbcSupport.getLocalDate(rs, "effectiveTo");
|
||||
result.setEffectiveTo(effectiveTo != null ? effectiveTo.toString() : null);
|
||||
final java.time.LocalDate endDate = JdbcSupport.getLocalDate(rs, "endDate");
|
||||
result.setEndDate(endDate != null ? endDate.toString() : null);
|
||||
result.setIntroducerRequired(rs.getBoolean("introducerRequired"));
|
||||
result.setShareLinkingEnabled(rs.getBoolean("shareLinkingEnabled"));
|
||||
result.setNominationFacility(rs.getBoolean("nominationFacility"));
|
||||
result.setDormancyAlert(rs.getBoolean("dormancyAlert"));
|
||||
result.setIsDormancyTrackingActive(rs.getBoolean("isDormancyTrackingActive"));
|
||||
result.setDaysToInactive(JdbcSupport.getLong(rs, "daysToInactive"));
|
||||
result.setDaysToDormancy(JdbcSupport.getLong(rs, "daysToDormancy"));
|
||||
result.setDaysToEscheat(JdbcSupport.getLong(rs, "daysToEscheat"));
|
||||
result.setInterestCalculateSelector(JdbcSupport.getInteger(rs, "interestCalculateSelector"));
|
||||
result.setAveragePeriod(rs.getString("averagePeriod"));
|
||||
result.setAutoPost(rs.getBoolean("autoPost"));
|
||||
result.setFrequencyFixDay(JdbcSupport.getInteger(rs, "frequencyFixDay"));
|
||||
final java.time.LocalDate lastInterestDate = JdbcSupport.getLocalDate(rs, "lastInterestDate");
|
||||
result.setLastInterestDate(lastInterestDate != null ? lastInterestDate.toString() : null);
|
||||
result.setEnableLockinPeriod(rs.getBoolean("enableLockinPeriod"));
|
||||
result.setBalanceFrequency(rs.getString("balanceFrequency"));
|
||||
result.setAccountClosedZeroBalanceInDayClosing(rs.getBoolean("accountClosedZeroBalanceInDayClosing"));
|
||||
result.setAutoDebitFacility(rs.getBoolean("autoDebitFacility"));
|
||||
result.setLoanFacility(rs.getBoolean("loanFacility"));
|
||||
result.setPrematureWithdrawalOption(rs.getBoolean("prematureWithdrawalOption"));
|
||||
result.setTenureFlexibility(rs.getBoolean("tenureFlexibility"));
|
||||
result.setLienMarked(rs.getBoolean("lienMarked"));
|
||||
result.setMaturityInstructions(rs.getBoolean("maturityInstructions"));
|
||||
result.setCreditMaturityProceeds(rs.getBoolean("creditMaturityProceeds"));
|
||||
result.setPenaltyGracePeriodMissedInstallments(rs.getBoolean("penaltyGracePeriodMissedInstallments"));
|
||||
result.setPanelRequestApplicable(rs.getBoolean("panelRequestApplicable"));
|
||||
result.setNoPenaltyNomineeHeirClosure(rs.getBoolean("noPenaltyNomineeHeirClosure"));
|
||||
result.setDeceasedSettlement(rs.getBoolean("deceasedSettlement"));
|
||||
result.setAllowDebitTxnAfterDueDate(rs.getBoolean("allowDebitTxnAfterDueDate"));
|
||||
result.setWithdrawalFeeForTransfers(rs.getBoolean("withdrawalFeeForTransfers"));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.service;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.fineract.portfolio.savings.api.FdInterestRateSaveRequest;
|
||||
import org.apache.fineract.portfolio.savings.data.FdInterestRateEffectiveData;
|
||||
|
||||
public interface FdBaseInterestRateReadPlatformService {
|
||||
|
||||
List<FdInterestRateEffectiveData> retrieveAllInterestRates();
|
||||
|
||||
List<FdInterestRateEffectiveData> retrieveAllActiveInterestRates();
|
||||
|
||||
List<FdInterestRateEffectiveData> retrieveActiveInterestRatesByType(String fdType);
|
||||
|
||||
FdInterestRateEffectiveData saveInterestRates(FdInterestRateSaveRequest request, Long createdById);
|
||||
}
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.portfolio.savings.api.FdInterestRateSaveRequest;
|
||||
import org.apache.fineract.portfolio.savings.data.FdInterestRateEffectiveData;
|
||||
import org.apache.fineract.portfolio.savings.data.FdInterestRateSlabData;
|
||||
import org.apache.fineract.portfolio.savings.domain.FdBaseInterestRateEffective;
|
||||
import org.apache.fineract.portfolio.savings.domain.FdBaseInterestRateEffectiveRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.FdBaseInterestRateSlabHistory;
|
||||
import org.apache.fineract.portfolio.savings.domain.FdBaseInterestRateSlabHistoryRepository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class FdBaseInterestRateReadPlatformServiceImpl implements FdBaseInterestRateReadPlatformService {
|
||||
|
||||
private final FdBaseInterestRateEffectiveRepository effectiveRepository;
|
||||
private final FdBaseInterestRateSlabHistoryRepository slabRepository;
|
||||
|
||||
@Override
|
||||
public List<FdInterestRateEffectiveData> retrieveAllInterestRates() {
|
||||
return effectiveRepository.findByOrderByEffectiveFromDateDesc().stream().map(this::toData).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FdInterestRateEffectiveData> retrieveAllActiveInterestRates() {
|
||||
return effectiveRepository.findByIsActiveTrueOrderByEffectiveFromDateDesc().stream().map(this::toData)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FdInterestRateEffectiveData> retrieveActiveInterestRatesByType(String fdType) {
|
||||
return effectiveRepository.findByFdTypeAndIsActiveTrueOrderByEffectiveFromDateDesc(fdType).stream().map(this::toData)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public FdInterestRateEffectiveData saveInterestRates(FdInterestRateSaveRequest request, Long createdById) {
|
||||
final String fdType = request.getFdType();
|
||||
final LocalDate today = LocalDate.now();
|
||||
|
||||
final List<FdBaseInterestRateEffective> activeVersions = effectiveRepository
|
||||
.findByFdTypeAndIsActiveTrueOrderByEffectiveFromDateDesc(fdType);
|
||||
for (FdBaseInterestRateEffective version : activeVersions) {
|
||||
version.deactivate(today);
|
||||
}
|
||||
if (!activeVersions.isEmpty()) {
|
||||
effectiveRepository.saveAll(activeVersions);
|
||||
}
|
||||
|
||||
final String label = request.getVersionLabel() != null && !request.getVersionLabel().isBlank()
|
||||
? request.getVersionLabel()
|
||||
: "FD " + fdType + " Rate Version " + LocalDate.now();
|
||||
|
||||
FdBaseInterestRateEffective newVersion = FdBaseInterestRateEffective.create(fdType, label, today, request.getRemarks(), createdById);
|
||||
newVersion = effectiveRepository.saveAndFlush(newVersion);
|
||||
|
||||
final Long versionId = newVersion.getId();
|
||||
int srCounter = 1;
|
||||
if (request.getSlabs() != null) {
|
||||
for (FdInterestRateSaveRequest.SlabRequest slabRequest : request.getSlabs()) {
|
||||
final int sr = slabRequest.getSrNo() != null ? slabRequest.getSrNo() : srCounter++;
|
||||
final FdBaseInterestRateSlabHistory slab = FdBaseInterestRateSlabHistory.create(versionId, sr,
|
||||
slabRequest.getDescription(), slabRequest.getPeriodTypeEnum(), slabRequest.getFromPeriod(),
|
||||
slabRequest.getToPeriod(), slabRequest.getAnnualInterestRate(), slabRequest.getSeniorCitizenRate());
|
||||
slabRepository.save(slab);
|
||||
}
|
||||
}
|
||||
|
||||
return toData(newVersion);
|
||||
}
|
||||
|
||||
private FdInterestRateEffectiveData toData(FdBaseInterestRateEffective e) {
|
||||
List<FdInterestRateSlabData> slabs = slabRepository.findByEffectiveIdOrderBySrNo(e.getId()).stream()
|
||||
.map(s -> FdInterestRateSlabData.builder()
|
||||
.id(s.getId())
|
||||
.srNo(s.getSrNo())
|
||||
.description(s.getDescription())
|
||||
.periodTypeEnum(s.getPeriodTypeEnum())
|
||||
.periodTypeLabel(periodLabel(s.getPeriodTypeEnum()))
|
||||
.fromPeriod(s.getFromPeriod())
|
||||
.toPeriod(s.getToPeriod())
|
||||
.annualInterestRate(s.getAnnualInterestRate())
|
||||
.seniorCitizenRate(s.getSeniorCitizenRate())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return FdInterestRateEffectiveData.builder()
|
||||
.id(e.getId())
|
||||
.fdType(e.getFdType())
|
||||
.versionLabel(e.getVersionLabel())
|
||||
.effectiveFromDate(e.getEffectiveFromDate())
|
||||
.effectiveToDate(e.getEffectiveToDate())
|
||||
.isActive(e.getIsActive())
|
||||
.remarks(e.getRemarks())
|
||||
.slabs(slabs)
|
||||
.build();
|
||||
}
|
||||
|
||||
private String periodLabel(Integer code) {
|
||||
if (code == null) {
|
||||
return "Days";
|
||||
}
|
||||
|
||||
return switch (code) {
|
||||
case 0 -> "Days";
|
||||
case 1 -> "Weeks";
|
||||
case 2 -> "Months";
|
||||
case 3 -> "Years";
|
||||
default -> "Days";
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
+1
-2
@@ -1391,8 +1391,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
public SavingsAccountData fallbackPostInterest(SavingsAccountData savingsAccountData, boolean postInterestAs, LocalDate transactionDate,
|
||||
boolean backdatedTxnsAllowedTill, Throwable t) {
|
||||
// NOTE: allow caller to catch the exceptions
|
||||
// NOTE: wrap throwable only if really necessary
|
||||
throw errorHandler.getMappable(t, null, null, "savings.postinterest");
|
||||
throw org.apache.fineract.infrastructure.core.exception.ErrorHandler.getMappable(t, null, null, "savings.postinterest");
|
||||
}
|
||||
|
||||
@Transactional
|
||||
|
||||
+12
@@ -146,8 +146,12 @@ import org.apache.fineract.portfolio.savings.service.SavingsProductWritePlatform
|
||||
import org.apache.fineract.portfolio.savings.service.SavingsProductWritePlatformServiceJpaRepositoryImpl;
|
||||
import org.apache.fineract.portfolio.savings.domain.RdBaseInterestRateEffectiveRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.RdBaseInterestRateSlabHistoryRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.FdBaseInterestRateEffectiveRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.FdBaseInterestRateSlabHistoryRepository;
|
||||
import org.apache.fineract.portfolio.savings.service.RdBaseInterestRateReadPlatformService;
|
||||
import org.apache.fineract.portfolio.savings.service.RdBaseInterestRateReadPlatformServiceImpl;
|
||||
import org.apache.fineract.portfolio.savings.service.FdBaseInterestRateReadPlatformService;
|
||||
import org.apache.fineract.portfolio.savings.service.FdBaseInterestRateReadPlatformServiceImpl;
|
||||
import org.apache.fineract.portfolio.savings.service.SavingsSchedularInterestPoster;
|
||||
import org.apache.fineract.portfolio.savings.service.SavingsSchedularInterestPosterTask;
|
||||
import org.apache.fineract.portfolio.savings.service.search.SavingsAccountTransactionSearchService;
|
||||
@@ -171,6 +175,14 @@ public class SavingsConfiguration {
|
||||
return new RdBaseInterestRateReadPlatformServiceImpl(effectiveRepository, slabRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(FdBaseInterestRateReadPlatformService.class)
|
||||
public FdBaseInterestRateReadPlatformService fdBaseInterestRateReadPlatformService(
|
||||
FdBaseInterestRateEffectiveRepository effectiveRepository,
|
||||
FdBaseInterestRateSlabHistoryRepository slabRepository) {
|
||||
return new FdBaseInterestRateReadPlatformServiceImpl(effectiveRepository, slabRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(SavingsAccountTransactionSearchService.class)
|
||||
public SavingsAccountTransactionSearchService savingsAccountTransactionSearchService(PlatformSecurityContext context,
|
||||
|
||||
@@ -286,4 +286,7 @@
|
||||
<include file="parts/0276_create_current_account_tables.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0277_fix_current_account_audit_columns.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/0280_add_fixed_deposit_product_codes.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0281_update_fd_base_interest_rate_seed_data.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
|
||||
+300
@@ -0,0 +1,300 @@
|
||||
<?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">
|
||||
|
||||
<!-- 1. Add fd_type column to m_savings_product -->
|
||||
<changeSet id="0279a_add_fd_type_to_savings_product" author="fineract">
|
||||
<validCheckSum>ANY</validCheckSum>
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not><columnExists tableName="m_savings_product" columnName="fd_type"/></not>
|
||||
</preConditions>
|
||||
<addColumn tableName="m_savings_product">
|
||||
<column name="fd_type" type="VARCHAR(20)" defaultValue="SINGLE">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<!-- 2. Create FD base interest rate effective (version) table -->
|
||||
<changeSet id="0279b_create_fd_base_interest_rate_effective" author="fineract">
|
||||
<validCheckSum>ANY</validCheckSum>
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not><tableExists tableName="m_fd_base_interest_rate_effective"/></not>
|
||||
</preConditions>
|
||||
<createTable tableName="m_fd_base_interest_rate_effective">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="fd_type" type="VARCHAR(20)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="version_label" type="VARCHAR(100)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="effective_from_date" type="DATE">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="effective_to_date" type="DATE"/>
|
||||
<column name="is_active" type="BOOLEAN" defaultValueBoolean="true">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="remarks" type="VARCHAR(500)"/>
|
||||
<column name="created_by_id" type="BIGINT"/>
|
||||
<column name="created_date" type="DATE"/>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
<!-- 3. Create FD base interest rate slab history table -->
|
||||
<changeSet id="0279c_create_fd_base_interest_rate_slab_history" author="fineract">
|
||||
<validCheckSum>ANY</validCheckSum>
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not><tableExists tableName="m_fd_base_interest_rate_slab_history"/></not>
|
||||
</preConditions>
|
||||
<createTable tableName="m_fd_base_interest_rate_slab_history">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="effective_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="sr_no" type="INT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="description" type="VARCHAR(200)"/>
|
||||
<!-- period_type_enum: 0=DAYS, 1=WEEKS, 2=MONTHS, 3=YEARS -->
|
||||
<column name="period_type_enum" type="INT" defaultValueNumeric="0">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="from_period" type="INT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="to_period" type="INT"/>
|
||||
<column name="annual_interest_rate" type="DECIMAL(19,6)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<!-- senior_citizen_rate: additional rate for senior citizens -->
|
||||
<column name="senior_citizen_rate" type="DECIMAL(19,6)" defaultValueNumeric="0"/>
|
||||
<column name="created_date" type="DATE"/>
|
||||
</createTable>
|
||||
<addForeignKeyConstraint
|
||||
baseTableName="m_fd_base_interest_rate_slab_history"
|
||||
baseColumnNames="effective_id"
|
||||
referencedTableName="m_fd_base_interest_rate_effective"
|
||||
referencedColumnNames="id"
|
||||
constraintName="fk_fd_base_rate_slab_effective"/>
|
||||
</changeSet>
|
||||
|
||||
<!-- 4. Seed initial FD base interest rate data -->
|
||||
<changeSet id="0279d_seed_fd_base_interest_rate_single" author="fineract">
|
||||
<validCheckSum>ANY</validCheckSum>
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_fd_base_interest_rate_effective WHERE fd_type = 'SINGLE'</sqlCheck>
|
||||
</preConditions>
|
||||
<!-- FD SINGLE: < 1 year, period in DAYS -->
|
||||
<insert tableName="m_fd_base_interest_rate_effective">
|
||||
<column name="fd_type" value="SINGLE"/>
|
||||
<column name="version_label" value="FD-SINGLE-V1"/>
|
||||
<column name="effective_from_date" value="2025-01-01"/>
|
||||
<column name="is_active" valueBoolean="true"/>
|
||||
<column name="remarks" value="Initial FD Single (Short Term) rates"/>
|
||||
<column name="created_date" valueDate="2025-01-01"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="0279e_seed_fd_single_slabs" author="fineract">
|
||||
<validCheckSum>ANY</validCheckSum>
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_fd_base_interest_rate_slab_history sh JOIN m_fd_base_interest_rate_effective e ON sh.effective_id = e.id WHERE e.fd_type = 'SINGLE'</sqlCheck>
|
||||
</preConditions>
|
||||
<!-- 1-29 days -->
|
||||
<insert tableName="m_fd_base_interest_rate_slab_history">
|
||||
<column name="effective_id" valueComputed="(SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type='SINGLE' AND version_label='FD-SINGLE-V1')"/>
|
||||
<column name="sr_no" valueNumeric="1"/>
|
||||
<column name="description" value="1 to 29 Days"/>
|
||||
<column name="period_type_enum" valueNumeric="0"/>
|
||||
<column name="from_period" valueNumeric="1"/>
|
||||
<column name="to_period" valueNumeric="29"/>
|
||||
<column name="annual_interest_rate" valueNumeric="4.50"/>
|
||||
<column name="senior_citizen_rate" valueNumeric="5.00"/>
|
||||
<column name="created_date" valueDate="2025-01-01"/>
|
||||
</insert>
|
||||
<!-- 30-89 days -->
|
||||
<insert tableName="m_fd_base_interest_rate_slab_history">
|
||||
<column name="effective_id" valueComputed="(SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type='SINGLE' AND version_label='FD-SINGLE-V1')"/>
|
||||
<column name="sr_no" valueNumeric="2"/>
|
||||
<column name="description" value="30 to 89 Days"/>
|
||||
<column name="period_type_enum" valueNumeric="0"/>
|
||||
<column name="from_period" valueNumeric="30"/>
|
||||
<column name="to_period" valueNumeric="89"/>
|
||||
<column name="annual_interest_rate" valueNumeric="5.00"/>
|
||||
<column name="senior_citizen_rate" valueNumeric="5.50"/>
|
||||
<column name="created_date" valueDate="2025-01-01"/>
|
||||
</insert>
|
||||
<!-- 90-179 days -->
|
||||
<insert tableName="m_fd_base_interest_rate_slab_history">
|
||||
<column name="effective_id" valueComputed="(SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type='SINGLE' AND version_label='FD-SINGLE-V1')"/>
|
||||
<column name="sr_no" valueNumeric="3"/>
|
||||
<column name="description" value="90 to 179 Days"/>
|
||||
<column name="period_type_enum" valueNumeric="0"/>
|
||||
<column name="from_period" valueNumeric="90"/>
|
||||
<column name="to_period" valueNumeric="179"/>
|
||||
<column name="annual_interest_rate" valueNumeric="5.50"/>
|
||||
<column name="senior_citizen_rate" valueNumeric="6.00"/>
|
||||
<column name="created_date" valueDate="2025-01-01"/>
|
||||
</insert>
|
||||
<!-- 180+ days -->
|
||||
<insert tableName="m_fd_base_interest_rate_slab_history">
|
||||
<column name="effective_id" valueComputed="(SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type='SINGLE' AND version_label='FD-SINGLE-V1')"/>
|
||||
<column name="sr_no" valueNumeric="4"/>
|
||||
<column name="description" value="180+ Days"/>
|
||||
<column name="period_type_enum" valueNumeric="0"/>
|
||||
<column name="from_period" valueNumeric="180"/>
|
||||
<column name="annual_interest_rate" valueNumeric="6.00"/>
|
||||
<column name="senior_citizen_rate" valueNumeric="6.50"/>
|
||||
<column name="created_date" valueDate="2025-01-01"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="0279f_seed_fd_base_interest_rate_double" author="fineract">
|
||||
<validCheckSum>ANY</validCheckSum>
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_fd_base_interest_rate_effective WHERE fd_type = 'DOUBLE'</sqlCheck>
|
||||
</preConditions>
|
||||
<!-- FD DOUBLE: >= 1 year, period in YEARS -->
|
||||
<insert tableName="m_fd_base_interest_rate_effective">
|
||||
<column name="fd_type" value="DOUBLE"/>
|
||||
<column name="version_label" value="FD-DOUBLE-V1"/>
|
||||
<column name="effective_from_date" value="2025-01-01"/>
|
||||
<column name="is_active" valueBoolean="true"/>
|
||||
<column name="remarks" value="Initial FD Double (Long Term) rates"/>
|
||||
<column name="created_date" valueDate="2025-01-01"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="0279g_seed_fd_double_slabs" author="fineract">
|
||||
<validCheckSum>ANY</validCheckSum>
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_fd_base_interest_rate_slab_history sh JOIN m_fd_base_interest_rate_effective e ON sh.effective_id = e.id WHERE e.fd_type = 'DOUBLE'</sqlCheck>
|
||||
</preConditions>
|
||||
<!-- 1-2 years -->
|
||||
<insert tableName="m_fd_base_interest_rate_slab_history">
|
||||
<column name="effective_id" valueComputed="(SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type='DOUBLE' AND version_label='FD-DOUBLE-V1')"/>
|
||||
<column name="sr_no" valueNumeric="1"/>
|
||||
<column name="description" value="1 to 2 Years"/>
|
||||
<column name="period_type_enum" valueNumeric="3"/>
|
||||
<column name="from_period" valueNumeric="1"/>
|
||||
<column name="to_period" valueNumeric="2"/>
|
||||
<column name="annual_interest_rate" valueNumeric="6.50"/>
|
||||
<column name="senior_citizen_rate" valueNumeric="7.00"/>
|
||||
<column name="created_date" valueDate="2025-01-01"/>
|
||||
</insert>
|
||||
<!-- 3-5 years -->
|
||||
<insert tableName="m_fd_base_interest_rate_slab_history">
|
||||
<column name="effective_id" valueComputed="(SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type='DOUBLE' AND version_label='FD-DOUBLE-V1')"/>
|
||||
<column name="sr_no" valueNumeric="2"/>
|
||||
<column name="description" value="3 to 5 Years"/>
|
||||
<column name="period_type_enum" valueNumeric="3"/>
|
||||
<column name="from_period" valueNumeric="3"/>
|
||||
<column name="to_period" valueNumeric="5"/>
|
||||
<column name="annual_interest_rate" valueNumeric="6.75"/>
|
||||
<column name="senior_citizen_rate" valueNumeric="7.25"/>
|
||||
<column name="created_date" valueDate="2025-01-01"/>
|
||||
</insert>
|
||||
<!-- 6-10 years -->
|
||||
<insert tableName="m_fd_base_interest_rate_slab_history">
|
||||
<column name="effective_id" valueComputed="(SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type='DOUBLE' AND version_label='FD-DOUBLE-V1')"/>
|
||||
<column name="sr_no" valueNumeric="3"/>
|
||||
<column name="description" value="6 to 10 Years"/>
|
||||
<column name="period_type_enum" valueNumeric="3"/>
|
||||
<column name="from_period" valueNumeric="6"/>
|
||||
<column name="to_period" valueNumeric="10"/>
|
||||
<column name="annual_interest_rate" valueNumeric="7.00"/>
|
||||
<column name="senior_citizen_rate" valueNumeric="7.50"/>
|
||||
<column name="created_date" valueDate="2025-01-01"/>
|
||||
</insert>
|
||||
<!-- 11+ years -->
|
||||
<insert tableName="m_fd_base_interest_rate_slab_history">
|
||||
<column name="effective_id" valueComputed="(SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type='DOUBLE' AND version_label='FD-DOUBLE-V1')"/>
|
||||
<column name="sr_no" valueNumeric="4"/>
|
||||
<column name="description" value="11+ Years"/>
|
||||
<column name="period_type_enum" valueNumeric="3"/>
|
||||
<column name="from_period" valueNumeric="11"/>
|
||||
<column name="annual_interest_rate" valueNumeric="7.25"/>
|
||||
<column name="senior_citizen_rate" valueNumeric="7.75"/>
|
||||
<column name="created_date" valueDate="2025-01-01"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="0279h_seed_fd_base_interest_rate_special" author="fineract">
|
||||
<validCheckSum>ANY</validCheckSum>
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_fd_base_interest_rate_effective WHERE fd_type = 'SPECIAL'</sqlCheck>
|
||||
</preConditions>
|
||||
<!-- FD SPECIAL: monthly interest payout, period in MONTHS -->
|
||||
<insert tableName="m_fd_base_interest_rate_effective">
|
||||
<column name="fd_type" value="SPECIAL"/>
|
||||
<column name="version_label" value="FD-SPECIAL-V1"/>
|
||||
<column name="effective_from_date" value="2025-01-01"/>
|
||||
<column name="is_active" valueBoolean="true"/>
|
||||
<column name="remarks" value="Initial FD Special (Monthly Payout) rates"/>
|
||||
<column name="created_date" valueDate="2025-01-01"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="0279i_seed_fd_special_slabs" author="fineract">
|
||||
<validCheckSum>ANY</validCheckSum>
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_fd_base_interest_rate_slab_history sh JOIN m_fd_base_interest_rate_effective e ON sh.effective_id = e.id WHERE e.fd_type = 'SPECIAL'</sqlCheck>
|
||||
</preConditions>
|
||||
<!-- 1-12 months -->
|
||||
<insert tableName="m_fd_base_interest_rate_slab_history">
|
||||
<column name="effective_id" valueComputed="(SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type='SPECIAL' AND version_label='FD-SPECIAL-V1')"/>
|
||||
<column name="sr_no" valueNumeric="1"/>
|
||||
<column name="description" value="1 to 12 Months"/>
|
||||
<column name="period_type_enum" valueNumeric="2"/>
|
||||
<column name="from_period" valueNumeric="1"/>
|
||||
<column name="to_period" valueNumeric="12"/>
|
||||
<column name="annual_interest_rate" valueNumeric="6.00"/>
|
||||
<column name="senior_citizen_rate" valueNumeric="6.50"/>
|
||||
<column name="created_date" valueDate="2025-01-01"/>
|
||||
</insert>
|
||||
<!-- 13-24 months -->
|
||||
<insert tableName="m_fd_base_interest_rate_slab_history">
|
||||
<column name="effective_id" valueComputed="(SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type='SPECIAL' AND version_label='FD-SPECIAL-V1')"/>
|
||||
<column name="sr_no" valueNumeric="2"/>
|
||||
<column name="description" value="13 to 24 Months"/>
|
||||
<column name="period_type_enum" valueNumeric="2"/>
|
||||
<column name="from_period" valueNumeric="13"/>
|
||||
<column name="to_period" valueNumeric="24"/>
|
||||
<column name="annual_interest_rate" valueNumeric="6.50"/>
|
||||
<column name="senior_citizen_rate" valueNumeric="7.00"/>
|
||||
<column name="created_date" valueDate="2025-01-01"/>
|
||||
</insert>
|
||||
<!-- 25-60 months -->
|
||||
<insert tableName="m_fd_base_interest_rate_slab_history">
|
||||
<column name="effective_id" valueComputed="(SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type='SPECIAL' AND version_label='FD-SPECIAL-V1')"/>
|
||||
<column name="sr_no" valueNumeric="3"/>
|
||||
<column name="description" value="25 to 60 Months"/>
|
||||
<column name="period_type_enum" valueNumeric="2"/>
|
||||
<column name="from_period" valueNumeric="25"/>
|
||||
<column name="to_period" valueNumeric="60"/>
|
||||
<column name="annual_interest_rate" valueNumeric="7.00"/>
|
||||
<column name="senior_citizen_rate" valueNumeric="7.50"/>
|
||||
<column name="created_date" valueDate="2025-01-01"/>
|
||||
</insert>
|
||||
<!-- 61+ months -->
|
||||
<insert tableName="m_fd_base_interest_rate_slab_history">
|
||||
<column name="effective_id" valueComputed="(SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type='SPECIAL' AND version_label='FD-SPECIAL-V1')"/>
|
||||
<column name="sr_no" valueNumeric="4"/>
|
||||
<column name="description" value="61+ Months"/>
|
||||
<column name="period_type_enum" valueNumeric="2"/>
|
||||
<column name="from_period" valueNumeric="61"/>
|
||||
<column name="annual_interest_rate" valueNumeric="7.25"/>
|
||||
<column name="senior_citizen_rate" valueNumeric="7.75"/>
|
||||
<column name="created_date" valueDate="2025-01-01"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
<?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">
|
||||
|
||||
<!-- FixedDepositProductAccountType code and values -->
|
||||
<changeSet id="0280a_add_fd_product_account_type_code" author="system">
|
||||
<validCheckSum>ANY</validCheckSum>
|
||||
<sql>
|
||||
INSERT INTO m_code (code_name, is_system_defined)
|
||||
SELECT 'FixedDepositProductAccountType', false
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_code WHERE code_name = 'FixedDepositProductAccountType');
|
||||
</sql>
|
||||
<sql>
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, is_active, is_mandatory)
|
||||
SELECT c.id, v.code_value, v.order_position, true, false
|
||||
FROM m_code c,
|
||||
(VALUES
|
||||
('Fd Account', 1)
|
||||
) AS v(code_value, order_position)
|
||||
WHERE c.code_name = 'FixedDepositProductAccountType'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM m_code_value cv
|
||||
WHERE cv.code_id = c.id AND cv.code_value = v.code_value
|
||||
);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<!-- FixedDepositProductCustomerSegment code and values -->
|
||||
<changeSet id="0280b_add_fd_product_customer_segment_code" author="system">
|
||||
<validCheckSum>ANY</validCheckSum>
|
||||
<sql>
|
||||
INSERT INTO m_code (code_name, is_system_defined)
|
||||
SELECT 'FixedDepositProductCustomerSegment', false
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_code WHERE code_name = 'FixedDepositProductCustomerSegment');
|
||||
</sql>
|
||||
<sql>
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, is_active, is_mandatory)
|
||||
SELECT c.id, v.code_value, v.order_position, true, false
|
||||
FROM m_code c,
|
||||
(VALUES
|
||||
('Individual', 1),
|
||||
('Non-Individual', 2)
|
||||
) AS v(code_value, order_position)
|
||||
WHERE c.code_name = 'FixedDepositProductCustomerSegment'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM m_code_value cv
|
||||
WHERE cv.code_id = c.id AND cv.code_value = v.code_value
|
||||
);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
<?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="0281_update_fd_base_interest_rate_seed_data" author="fineract">
|
||||
<validCheckSum>ANY</validCheckSum>
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<tableExists tableName="m_fd_base_interest_rate_effective"/>
|
||||
</preConditions>
|
||||
|
||||
<sql>
|
||||
UPDATE m_fd_base_interest_rate_slab_history
|
||||
SET description = '1 to 29 Days',
|
||||
from_period = 1,
|
||||
to_period = 29
|
||||
WHERE effective_id = (SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type = 'SINGLE' AND version_label = 'FD-SINGLE-V1')
|
||||
AND sr_no = 1;
|
||||
|
||||
UPDATE m_fd_base_interest_rate_slab_history
|
||||
SET description = '30 to 89 Days',
|
||||
from_period = 30,
|
||||
to_period = 89
|
||||
WHERE effective_id = (SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type = 'SINGLE' AND version_label = 'FD-SINGLE-V1')
|
||||
AND sr_no = 2;
|
||||
|
||||
UPDATE m_fd_base_interest_rate_slab_history
|
||||
SET description = '90 to 179 Days',
|
||||
from_period = 90,
|
||||
to_period = 179
|
||||
WHERE effective_id = (SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type = 'SINGLE' AND version_label = 'FD-SINGLE-V1')
|
||||
AND sr_no = 3;
|
||||
|
||||
UPDATE m_fd_base_interest_rate_slab_history
|
||||
SET description = '180+ Days',
|
||||
from_period = 180,
|
||||
to_period = NULL
|
||||
WHERE effective_id = (SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type = 'SINGLE' AND version_label = 'FD-SINGLE-V1')
|
||||
AND sr_no = 4;
|
||||
|
||||
UPDATE m_fd_base_interest_rate_slab_history
|
||||
SET description = '1 to 2 Years',
|
||||
from_period = 1,
|
||||
to_period = 2
|
||||
WHERE effective_id = (SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type = 'DOUBLE' AND version_label = 'FD-DOUBLE-V1')
|
||||
AND sr_no = 1;
|
||||
|
||||
UPDATE m_fd_base_interest_rate_slab_history
|
||||
SET description = '3 to 5 Years',
|
||||
from_period = 3,
|
||||
to_period = 5
|
||||
WHERE effective_id = (SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type = 'DOUBLE' AND version_label = 'FD-DOUBLE-V1')
|
||||
AND sr_no = 2;
|
||||
|
||||
UPDATE m_fd_base_interest_rate_slab_history
|
||||
SET description = '6 to 10 Years',
|
||||
from_period = 6,
|
||||
to_period = 10
|
||||
WHERE effective_id = (SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type = 'DOUBLE' AND version_label = 'FD-DOUBLE-V1')
|
||||
AND sr_no = 3;
|
||||
|
||||
UPDATE m_fd_base_interest_rate_slab_history
|
||||
SET description = '11+ Years',
|
||||
from_period = 11,
|
||||
to_period = NULL
|
||||
WHERE effective_id = (SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type = 'DOUBLE' AND version_label = 'FD-DOUBLE-V1')
|
||||
AND sr_no = 4;
|
||||
|
||||
UPDATE m_fd_base_interest_rate_slab_history
|
||||
SET description = '1 to 12 Months',
|
||||
from_period = 1,
|
||||
to_period = 12
|
||||
WHERE effective_id = (SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type = 'SPECIAL' AND version_label = 'FD-SPECIAL-V1')
|
||||
AND sr_no = 1;
|
||||
|
||||
UPDATE m_fd_base_interest_rate_slab_history
|
||||
SET description = '13 to 24 Months',
|
||||
from_period = 13,
|
||||
to_period = 24
|
||||
WHERE effective_id = (SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type = 'SPECIAL' AND version_label = 'FD-SPECIAL-V1')
|
||||
AND sr_no = 2;
|
||||
|
||||
UPDATE m_fd_base_interest_rate_slab_history
|
||||
SET description = '25 to 60 Months',
|
||||
from_period = 25,
|
||||
to_period = 60
|
||||
WHERE effective_id = (SELECT id FROM m_fd_base_interest_rate_effective WHERE fd_type = 'SPECIAL' AND version_label = 'FD-SPECIAL-V1')
|
||||
AND sr_no = 3;
|
||||
|
||||
INSERT INTO m_fd_base_interest_rate_slab_history
|
||||
(effective_id, sr_no, description, period_type_enum, from_period, to_period, annual_interest_rate, senior_citizen_rate, created_date)
|
||||
SELECT e.id, 4, '61+ Months', 2, 61, NULL, 7.250000, 7.750000, CURRENT_DATE
|
||||
FROM m_fd_base_interest_rate_effective e
|
||||
WHERE e.fd_type = 'SPECIAL' AND e.version_label = 'FD-SPECIAL-V1'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM m_fd_base_interest_rate_slab_history sh
|
||||
WHERE sh.effective_id = e.id
|
||||
AND sh.sr_no = 4
|
||||
);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+4
-1
@@ -45,6 +45,7 @@ import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccount;
|
||||
import org.apache.fineract.portfolio.shareproducts.domain.ShareProduct;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
public class AccountNumberGeneratorTest {
|
||||
|
||||
@@ -54,6 +55,7 @@ public class AccountNumberGeneratorTest {
|
||||
private SavingsAccountRepository savingsRepo;
|
||||
private GLAccountRepository glAccountRepo;
|
||||
private SavingsProductRepository savingsProductRepo;
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
private AccountNumberGenerator generator;
|
||||
|
||||
@@ -65,8 +67,9 @@ public class AccountNumberGeneratorTest {
|
||||
savingsRepo = mock(SavingsAccountRepository.class);
|
||||
glAccountRepo = mock(GLAccountRepository.class);
|
||||
savingsProductRepo = mock(SavingsProductRepository.class);
|
||||
jdbcTemplate = mock(JdbcTemplate.class);
|
||||
|
||||
generator = new AccountNumberGenerator(configService, clientRepo, loanRepo, savingsRepo, glAccountRepo, savingsProductRepo);
|
||||
generator = new AccountNumberGenerator(configService, clientRepo, loanRepo, savingsRepo, glAccountRepo, savingsProductRepo, jdbcTemplate);
|
||||
|
||||
GlobalConfigurationPropertyData accountLengthConfig = mock(GlobalConfigurationPropertyData.class);
|
||||
when(accountLengthConfig.getValue()).thenReturn(Long.valueOf("9"));
|
||||
|
||||
+177
-14
@@ -112,9 +112,9 @@ public final class FixedDepositProductData extends DepositProductData {
|
||||
}
|
||||
|
||||
public static FixedDepositProductData withCharges(final FixedDepositProductData existingProduct, final Collection<ChargeData> charges) {
|
||||
return new FixedDepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName, existingProduct.description,
|
||||
existingProduct.currency, existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
|
||||
existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
final FixedDepositProductData result = new FixedDepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName,
|
||||
existingProduct.description, existingProduct.currency, existingProduct.nominalAnnualInterestRate,
|
||||
existingProduct.interestCompoundingPeriodType, existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
existingProduct.interestCalculationDaysInYearType, existingProduct.lockinPeriodFrequency,
|
||||
existingProduct.lockinPeriodFrequencyType, existingProduct.minBalanceForInterestCalculation, existingProduct.accountingRule,
|
||||
existingProduct.accountingMappings, existingProduct.paymentChannelToFundSourceMappings, existingProduct.currencyOptions,
|
||||
@@ -131,6 +131,8 @@ public final class FixedDepositProductData extends DepositProductData {
|
||||
existingProduct.minDepositAmount, existingProduct.depositAmount, existingProduct.maxDepositAmount,
|
||||
existingProduct.periodFrequencyTypeOptions, existingProduct.withHoldTax, existingProduct.taxGroup,
|
||||
existingProduct.taxGroupOptions);
|
||||
result.copyCbsFieldsFrom(existingProduct);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,9 +154,9 @@ public final class FixedDepositProductData extends DepositProductData {
|
||||
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions,
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions, final Collection<TaxGroupData> taxGroupOptions) {
|
||||
|
||||
return new FixedDepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName, existingProduct.description,
|
||||
existingProduct.currency, existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
|
||||
existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
final FixedDepositProductData result = new FixedDepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName,
|
||||
existingProduct.description, existingProduct.currency, existingProduct.nominalAnnualInterestRate,
|
||||
existingProduct.interestCompoundingPeriodType, existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
existingProduct.interestCalculationDaysInYearType, existingProduct.lockinPeriodFrequency,
|
||||
existingProduct.lockinPeriodFrequencyType, existingProduct.minBalanceForInterestCalculation, existingProduct.accountingRule,
|
||||
existingProduct.accountingMappings, existingProduct.paymentChannelToFundSourceMappings, currencyOptions,
|
||||
@@ -169,6 +171,8 @@ public final class FixedDepositProductData extends DepositProductData {
|
||||
existingProduct.inMultiplesOfDepositTermType, existingProduct.minDepositAmount, existingProduct.depositAmount,
|
||||
existingProduct.maxDepositAmount, periodFrequencyTypeOptions, existingProduct.withHoldTax, existingProduct.taxGroup,
|
||||
taxGroupOptions);
|
||||
result.copyCbsFieldsFrom(existingProduct);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static FixedDepositProductData withAccountingDetails(final FixedDepositProductData existingProduct,
|
||||
@@ -189,9 +193,9 @@ public final class FixedDepositProductData extends DepositProductData {
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
final Collection<ChargeData> penaltyOptions = null;
|
||||
|
||||
return new FixedDepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName, existingProduct.description,
|
||||
existingProduct.currency, existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
|
||||
existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
final FixedDepositProductData result = new FixedDepositProductData(existingProduct.id, existingProduct.name,
|
||||
existingProduct.shortName, existingProduct.description, existingProduct.currency, existingProduct.nominalAnnualInterestRate,
|
||||
existingProduct.interestCompoundingPeriodType, existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
existingProduct.interestCalculationDaysInYearType, existingProduct.lockinPeriodFrequency,
|
||||
existingProduct.lockinPeriodFrequencyType, existingProduct.minBalanceForInterestCalculation, existingProduct.accountingRule,
|
||||
accountingMappings, paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions,
|
||||
@@ -206,6 +210,8 @@ public final class FixedDepositProductData extends DepositProductData {
|
||||
existingProduct.minDepositAmount, existingProduct.depositAmount, existingProduct.maxDepositAmount,
|
||||
existingProduct.periodFrequencyTypeOptions, existingProduct.withHoldTax, existingProduct.taxGroup,
|
||||
existingProduct.taxGroupOptions);
|
||||
result.copyCbsFieldsFrom(existingProduct);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static FixedDepositProductData instance(final DepositProductData depositProductData, final boolean preClosurePenalApplicable,
|
||||
@@ -243,7 +249,7 @@ public final class FixedDepositProductData extends DepositProductData {
|
||||
depositProductData.interestCompoundingPeriodType, depositProductData.interestPostingPeriodType,
|
||||
depositProductData.interestCalculationType, depositProductData.interestCalculationDaysInYearType,
|
||||
depositProductData.lockinPeriodFrequency, depositProductData.lockinPeriodFrequencyType,
|
||||
depositProductData.minBalanceForInterestCalculation, depositProductData.accountingRule, accountingMappings,
|
||||
depositProductData.getMinBalanceForInterestCalculation(), depositProductData.accountingRule, accountingMappings,
|
||||
paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions, accountingMappingOptions, charges, chargeOptions,
|
||||
@@ -321,9 +327,9 @@ public final class FixedDepositProductData extends DepositProductData {
|
||||
|
||||
public static FixedDepositProductData withInterestChart(final FixedDepositProductData existingProduct,
|
||||
final Collection<InterestRateChartData> interestRateCharts) {
|
||||
return new FixedDepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName, existingProduct.description,
|
||||
existingProduct.currency, existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
|
||||
existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
final FixedDepositProductData result = new FixedDepositProductData(existingProduct.id, existingProduct.name,
|
||||
existingProduct.shortName, existingProduct.description, existingProduct.currency, existingProduct.nominalAnnualInterestRate,
|
||||
existingProduct.interestCompoundingPeriodType, existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
existingProduct.interestCalculationDaysInYearType, existingProduct.lockinPeriodFrequency,
|
||||
existingProduct.lockinPeriodFrequencyType, existingProduct.minBalanceForInterestCalculation, existingProduct.accountingRule,
|
||||
existingProduct.accountingMappings, existingProduct.paymentChannelToFundSourceMappings, existingProduct.currencyOptions,
|
||||
@@ -340,7 +346,8 @@ public final class FixedDepositProductData extends DepositProductData {
|
||||
existingProduct.minDepositAmount, existingProduct.depositAmount, existingProduct.maxDepositAmount,
|
||||
existingProduct.periodFrequencyTypeOptions, existingProduct.withHoldTax, existingProduct.taxGroup,
|
||||
existingProduct.taxGroupOptions);
|
||||
|
||||
result.copyCbsFieldsFrom(existingProduct);
|
||||
return result;
|
||||
}
|
||||
|
||||
private FixedDepositProductData(final Long id, final String name, final String shortName, final String description,
|
||||
@@ -445,4 +452,160 @@ public final class FixedDepositProductData extends DepositProductData {
|
||||
return preClosurePenalApplicable;
|
||||
}
|
||||
|
||||
// CBS Custom Fields
|
||||
private Collection<org.apache.fineract.infrastructure.core.data.EnumOptionData> interestCalculationTypeOption;
|
||||
private Collection<org.apache.fineract.infrastructure.core.data.EnumOptionData> periodFrequencyOptions;
|
||||
private java.util.List<org.apache.fineract.infrastructure.codes.data.CodeValueData> yesNoOptions;
|
||||
private java.util.List<org.apache.fineract.infrastructure.codes.data.CodeValueData> accountTypeOptions;
|
||||
private java.util.List<org.apache.fineract.infrastructure.codes.data.CodeValueData> customerSegmentOptions;
|
||||
private String productCode;
|
||||
private String accountType;
|
||||
private String fdType;
|
||||
private Long glAccountId;
|
||||
private String glAccountName;
|
||||
private String customerSegment;
|
||||
private Boolean introducerRequired;
|
||||
private Boolean shareLinkingEnabled;
|
||||
private Boolean nominationFacility;
|
||||
private Boolean dormancyAlert;
|
||||
private Boolean isDormancyTrackingActive;
|
||||
private Long daysToInactive;
|
||||
private Long daysToDormancy;
|
||||
private Long daysToEscheat;
|
||||
private String effectiveDate;
|
||||
private String effectiveTo;
|
||||
private String endDate;
|
||||
private Integer interestCalculateSelector;
|
||||
private String averagePeriod;
|
||||
private Boolean autoPost;
|
||||
private Integer frequencyFixDay;
|
||||
private String lastInterestDate;
|
||||
private Boolean enableLockinPeriod;
|
||||
private Boolean autoDebitFacility;
|
||||
private Boolean loanFacility;
|
||||
private Boolean prematureWithdrawalOption;
|
||||
private Boolean tenureFlexibility;
|
||||
private Boolean lienMarked;
|
||||
private Boolean maturityInstructions;
|
||||
private Boolean creditMaturityProceeds;
|
||||
private Boolean penaltyGracePeriodMissedInstallments;
|
||||
private Boolean panelRequestApplicable;
|
||||
private Boolean noPenaltyNomineeHeirClosure;
|
||||
private Boolean deceasedSettlement;
|
||||
private Boolean allowDebitTxnAfterDueDate;
|
||||
private Boolean accountClosedZeroBalanceInDayClosing;
|
||||
private String balanceFrequency;
|
||||
|
||||
// Template option setters
|
||||
public void setInterestCalculationTypeOption(Collection<org.apache.fineract.infrastructure.core.data.EnumOptionData> v) { this.interestCalculationTypeOption = v; }
|
||||
public void setPeriodFrequencyOptions(Collection<org.apache.fineract.infrastructure.core.data.EnumOptionData> v) { this.periodFrequencyOptions = v; }
|
||||
public void setYesNoOptions(java.util.List<org.apache.fineract.infrastructure.codes.data.CodeValueData> v) { this.yesNoOptions = v; }
|
||||
public void setAccountTypeOptions(java.util.List<org.apache.fineract.infrastructure.codes.data.CodeValueData> v) { this.accountTypeOptions = v; }
|
||||
public void setCustomerSegmentOptions(java.util.List<org.apache.fineract.infrastructure.codes.data.CodeValueData> v) { this.customerSegmentOptions = v; }
|
||||
|
||||
// CBS field setters
|
||||
public void setProductCode(String v) { this.productCode = v; }
|
||||
public void setAccountType(String v) { this.accountType = v; }
|
||||
public void setFdType(String v) { this.fdType = v; }
|
||||
public void setGlAccountId(Long v) { this.glAccountId = v; }
|
||||
public void setGlAccountName(String v) { this.glAccountName = v; }
|
||||
public void setCustomerSegment(String v) { this.customerSegment = v; }
|
||||
public void setIntroducerRequired(Boolean v) { this.introducerRequired = v; }
|
||||
public void setShareLinkingEnabled(Boolean v) { this.shareLinkingEnabled = v; }
|
||||
public void setNominationFacility(Boolean v) { this.nominationFacility = v; }
|
||||
public void setDormancyAlert(Boolean v) { this.dormancyAlert = v; }
|
||||
public void setIsDormancyTrackingActive(Boolean v) { this.isDormancyTrackingActive = v; }
|
||||
public void setDaysToInactive(Long v) { this.daysToInactive = v; }
|
||||
public void setDaysToDormancy(Long v) { this.daysToDormancy = v; }
|
||||
public void setDaysToEscheat(Long v) { this.daysToEscheat = v; }
|
||||
public void setEffectiveDate(String v) { this.effectiveDate = v; }
|
||||
public void setEffectiveTo(String v) { this.effectiveTo = v; }
|
||||
public void setEndDate(String v) { this.endDate = v; }
|
||||
public void setInterestCalculateSelector(Integer v) { this.interestCalculateSelector = v; }
|
||||
public void setAveragePeriod(String v) { this.averagePeriod = v; }
|
||||
public void setAutoPost(Boolean v) { this.autoPost = v; }
|
||||
public void setFrequencyFixDay(Integer v) { this.frequencyFixDay = v; }
|
||||
public void setLastInterestDate(String v) { this.lastInterestDate = v; }
|
||||
public void setEnableLockinPeriod(Boolean v) { this.enableLockinPeriod = v; }
|
||||
public void setAutoDebitFacility(Boolean v) { this.autoDebitFacility = v; }
|
||||
public void setLoanFacility(Boolean v) { this.loanFacility = v; }
|
||||
public void setPrematureWithdrawalOption(Boolean v) { this.prematureWithdrawalOption = v; }
|
||||
public void setTenureFlexibility(Boolean v) { this.tenureFlexibility = v; }
|
||||
public void setLienMarked(Boolean v) { this.lienMarked = v; }
|
||||
public void setMaturityInstructions(Boolean v) { this.maturityInstructions = v; }
|
||||
public void setCreditMaturityProceeds(Boolean v) { this.creditMaturityProceeds = v; }
|
||||
public void setPenaltyGracePeriodMissedInstallments(Boolean v) { this.penaltyGracePeriodMissedInstallments = v; }
|
||||
public void setPanelRequestApplicable(Boolean v) { this.panelRequestApplicable = v; }
|
||||
public void setNoPenaltyNomineeHeirClosure(Boolean v) { this.noPenaltyNomineeHeirClosure = v; }
|
||||
public void setDeceasedSettlement(Boolean v) { this.deceasedSettlement = v; }
|
||||
public void setAllowDebitTxnAfterDueDate(Boolean v) { this.allowDebitTxnAfterDueDate = v; }
|
||||
public void setAccountClosedZeroBalanceInDayClosing(Boolean v) { this.accountClosedZeroBalanceInDayClosing = v; }
|
||||
public void setBalanceFrequency(String v) { this.balanceFrequency = v; }
|
||||
|
||||
// CBS field getters
|
||||
public String getProductCode() { return productCode; }
|
||||
public String getAccountType() { return accountType; }
|
||||
public String getFdType() { return fdType; }
|
||||
public Long getGlAccountId() { return glAccountId; }
|
||||
public String getGlAccountName() { return glAccountName; }
|
||||
public String getCustomerSegment() { return customerSegment; }
|
||||
public Boolean getIntroducerRequired() { return introducerRequired; }
|
||||
public Boolean getShareLinkingEnabled() { return shareLinkingEnabled; }
|
||||
public Boolean getNominationFacility() { return nominationFacility; }
|
||||
public Boolean getDormancyAlert() { return dormancyAlert; }
|
||||
public Boolean getIsDormancyTrackingActive() { return isDormancyTrackingActive; }
|
||||
public Long getDaysToInactive() { return daysToInactive; }
|
||||
public Long getDaysToDormancy() { return daysToDormancy; }
|
||||
public Long getDaysToEscheat() { return daysToEscheat; }
|
||||
|
||||
public void copyCbsFieldsFrom(FixedDepositProductData src) {
|
||||
if (src == null) return;
|
||||
this.accountType = src.accountType;
|
||||
this.fdType = src.fdType;
|
||||
this.customerSegmentOptions = src.customerSegmentOptions;
|
||||
this.productCode = src.productCode;
|
||||
this.glAccountId = src.glAccountId;
|
||||
this.glAccountName = src.glAccountName;
|
||||
this.interestCalculationTypeOption = src.interestCalculationTypeOption;
|
||||
this.periodFrequencyOptions = src.periodFrequencyOptions;
|
||||
this.yesNoOptions = src.yesNoOptions;
|
||||
this.accountTypeOptions = src.accountTypeOptions;
|
||||
this.customerSegment = src.customerSegment;
|
||||
this.introducerRequired = src.introducerRequired;
|
||||
this.shareLinkingEnabled = src.shareLinkingEnabled;
|
||||
this.nominationFacility = src.nominationFacility;
|
||||
this.dormancyAlert = src.dormancyAlert;
|
||||
this.isDormancyTrackingActive = src.isDormancyTrackingActive;
|
||||
this.daysToInactive = src.daysToInactive;
|
||||
this.daysToDormancy = src.daysToDormancy;
|
||||
this.daysToEscheat = src.daysToEscheat;
|
||||
this.effectiveDate = src.effectiveDate;
|
||||
this.effectiveTo = src.effectiveTo;
|
||||
this.endDate = src.endDate;
|
||||
this.interestCalculateSelector = src.interestCalculateSelector;
|
||||
this.averagePeriod = src.averagePeriod;
|
||||
this.autoPost = src.autoPost;
|
||||
this.frequencyFixDay = src.frequencyFixDay;
|
||||
this.lastInterestDate = src.lastInterestDate;
|
||||
this.enableLockinPeriod = src.enableLockinPeriod;
|
||||
this.autoDebitFacility = src.autoDebitFacility;
|
||||
this.loanFacility = src.loanFacility;
|
||||
this.prematureWithdrawalOption = src.prematureWithdrawalOption;
|
||||
this.tenureFlexibility = src.tenureFlexibility;
|
||||
this.lienMarked = src.lienMarked;
|
||||
this.maturityInstructions = src.maturityInstructions;
|
||||
this.creditMaturityProceeds = src.creditMaturityProceeds;
|
||||
this.penaltyGracePeriodMissedInstallments = src.penaltyGracePeriodMissedInstallments;
|
||||
this.panelRequestApplicable = src.panelRequestApplicable;
|
||||
this.noPenaltyNomineeHeirClosure = src.noPenaltyNomineeHeirClosure;
|
||||
this.deceasedSettlement = src.deceasedSettlement;
|
||||
this.allowDebitTxnAfterDueDate = src.allowDebitTxnAfterDueDate;
|
||||
this.accountClosedZeroBalanceInDayClosing = src.accountClosedZeroBalanceInDayClosing;
|
||||
this.balanceFrequency = src.balanceFrequency;
|
||||
this.withdrawalFeeForTransfers = src.withdrawalFeeForTransfers;
|
||||
}
|
||||
|
||||
private Boolean withdrawalFeeForTransfers;
|
||||
public void setWithdrawalFeeForTransfers(Boolean v) { this.withdrawalFeeForTransfers = v; }
|
||||
public Boolean getWithdrawalFeeForTransfers() { return withdrawalFeeForTransfers; }
|
||||
}
|
||||
|
||||
+63
@@ -187,6 +187,65 @@ public class DepositProductAssembler {
|
||||
// update product reference
|
||||
productTermAndPreClosure.updateProductReference(fixedDepositProduct);
|
||||
|
||||
// CBS Custom Fields
|
||||
fixedDepositProduct.setAccountType(command.stringValueOfParameterNamed("accountType"));
|
||||
fixedDepositProduct.setCustomerSegment(command.stringValueOfParameterNamed("customerSegment"));
|
||||
final String fdProductCode = command.stringValueOfParameterNamed("productCode");
|
||||
fixedDepositProduct.setProductCode((fdProductCode != null && !fdProductCode.isBlank()) ? fdProductCode : null);
|
||||
final String fdType = command.stringValueOfParameterNamed("fdType");
|
||||
fixedDepositProduct.setFdType((fdType != null && !fdType.isBlank()) ? fdType : null);
|
||||
if (command.parameterExists("glAccountId")) {
|
||||
fixedDepositProduct.setGlAccountId(command.longValueOfParameterNamed("glAccountId"));
|
||||
}
|
||||
fixedDepositProduct.setIntroducerRequired(command.booleanPrimitiveValueOfParameterNamed("introducerRequired"));
|
||||
fixedDepositProduct.setShareLinkingEnabled(command.booleanPrimitiveValueOfParameterNamed("shareLinkingEnabled"));
|
||||
fixedDepositProduct.setEffectiveDate(parseCbsDate(command.stringValueOfParameterNamed("effectiveDate")));
|
||||
fixedDepositProduct.setEffectiveTo(parseCbsDate(command.stringValueOfParameterNamed("effectiveTo")));
|
||||
fixedDepositProduct.setEndDate(parseCbsDate(command.stringValueOfParameterNamed("endDate")));
|
||||
fixedDepositProduct.setNominationFacility(command.booleanPrimitiveValueOfParameterNamed("nominationFacility"));
|
||||
final boolean dormancyAlertValue = command.booleanPrimitiveValueOfParameterNamed("dormancyAlert");
|
||||
fixedDepositProduct.setDormancyAlert(dormancyAlertValue);
|
||||
// isDormancyTrackingActive is driven by dormancyAlert for FD products (same as RD)
|
||||
fixedDepositProduct.setIsDormancyTrackingActive(dormancyAlertValue);
|
||||
if (command.parameterExists("daysToInactive")) {
|
||||
fixedDepositProduct.setDaysToInactive(command.longValueOfParameterNamed("daysToInactive"));
|
||||
}
|
||||
if (command.parameterExists("daysToDormancy")) {
|
||||
fixedDepositProduct.setDaysToDormancy(command.longValueOfParameterNamed("daysToDormancy"));
|
||||
}
|
||||
if (command.parameterExists("daysToEscheat")) {
|
||||
fixedDepositProduct.setDaysToEscheat(command.longValueOfParameterNamed("daysToEscheat"));
|
||||
}
|
||||
fixedDepositProduct.setInterestCalculateSelector(command.integerValueOfParameterNamed("interestCalculateSelector"));
|
||||
fixedDepositProduct.setAveragePeriod(command.stringValueOfParameterNamed("averagePeriod"));
|
||||
fixedDepositProduct.setAutoPost(command.booleanPrimitiveValueOfParameterNamed("autoPost"));
|
||||
fixedDepositProduct.setFrequencyFixDay(command.integerValueOfParameterNamed("frequencyFixDay"));
|
||||
fixedDepositProduct.setLastInterestDate(parseCbsDate(command.stringValueOfParameterNamed("lastInterestDate")));
|
||||
fixedDepositProduct.setEnableLockinPeriod(command.booleanPrimitiveValueOfParameterNamed("enableLockinPeriod"));
|
||||
fixedDepositProduct.setAutoDebitFacility(command.booleanPrimitiveValueOfParameterNamed("autoDebitFacility"));
|
||||
fixedDepositProduct.setLoanFacility(command.booleanPrimitiveValueOfParameterNamed("loanFacility"));
|
||||
fixedDepositProduct.setPrematureWithdrawalOption(command.booleanPrimitiveValueOfParameterNamed("prematureWithdrawalOption"));
|
||||
fixedDepositProduct.setTenureFlexibility(command.booleanPrimitiveValueOfParameterNamed("tenureFlexibility"));
|
||||
fixedDepositProduct.setLienMarked(command.booleanPrimitiveValueOfParameterNamed("lienMarked"));
|
||||
fixedDepositProduct.setMaturityInstructions(command.booleanPrimitiveValueOfParameterNamed("maturityInstructions"));
|
||||
fixedDepositProduct.setCreditMaturityProceeds(command.booleanPrimitiveValueOfParameterNamed("creditMaturityProceeds"));
|
||||
fixedDepositProduct.setPenaltyGracePeriodMissedInstallments(
|
||||
command.booleanPrimitiveValueOfParameterNamed("penaltyGracePeriodMissedInstallments"));
|
||||
fixedDepositProduct.setPanelRequestApplicable(command.booleanPrimitiveValueOfParameterNamed("panelRequestApplicable"));
|
||||
fixedDepositProduct.setNoPenaltyNomineeHeirClosure(
|
||||
command.booleanPrimitiveValueOfParameterNamed("noPenaltyNomineeHeirClosure"));
|
||||
fixedDepositProduct.setDeceasedSettlement(command.booleanPrimitiveValueOfParameterNamed("deceasedSettlement"));
|
||||
fixedDepositProduct.setAllowDebitTxnAfterDueDate(command.booleanPrimitiveValueOfParameterNamed("allowDebitTxnAfterDueDate"));
|
||||
if (command.parameterExists("accountClosedZeroBalanceInDayClosing")) {
|
||||
fixedDepositProduct.setAccountClosedZeroBalanceInDayClosing(
|
||||
command.booleanPrimitiveValueOfParameterNamed("accountClosedZeroBalanceInDayClosing"));
|
||||
}
|
||||
fixedDepositProduct.setBalanceFrequency(command.stringValueOfParameterNamed("balanceFrequency"));
|
||||
|
||||
if (command.parameterExists("withdrawalFeeForTransfers")) {
|
||||
fixedDepositProduct.setWithdrawalFeeApplicableForTransfer(command.booleanPrimitiveValueOfParameterNamed("withdrawalFeeForTransfers"));
|
||||
}
|
||||
|
||||
fixedDepositProduct.validateDomainRules();
|
||||
|
||||
return fixedDepositProduct;
|
||||
@@ -337,6 +396,10 @@ public class DepositProductAssembler {
|
||||
recurringDepositProduct.setDeceasedSettlement(command.booleanPrimitiveValueOfParameterNamed("deceasedSettlement"));
|
||||
recurringDepositProduct.setAllowDebitTxnAfterDueDate(command.booleanPrimitiveValueOfParameterNamed("allowDebitTxnAfterDueDate"));
|
||||
|
||||
if (command.parameterExists("withdrawalFeeForTransfers")) {
|
||||
recurringDepositProduct.setWithdrawalFeeApplicableForTransfer(command.booleanPrimitiveValueOfParameterNamed("withdrawalFeeForTransfers"));
|
||||
}
|
||||
|
||||
recurringDepositProduct.validateDomainRules();
|
||||
|
||||
return recurringDepositProduct;
|
||||
|
||||
+19
@@ -26,6 +26,7 @@ import static org.apache.fineract.portfolio.savings.DepositsApiConstants.maxDepo
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.DiscriminatorValue;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
@@ -34,6 +35,7 @@ import jakarta.persistence.JoinTable;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Transient;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
@@ -76,6 +78,17 @@ public class FixedDepositProduct extends SavingsProduct {
|
||||
@Transient
|
||||
protected InterestRateChartAssembler chartAssembler;
|
||||
|
||||
@Column(name = "fd_type", length = 50)
|
||||
private String fdType;
|
||||
|
||||
public String getFdType() {
|
||||
return fdType;
|
||||
}
|
||||
|
||||
public void setFdType(String fdType) {
|
||||
this.fdType = fdType;
|
||||
}
|
||||
|
||||
protected FixedDepositProduct() {
|
||||
|
||||
}
|
||||
@@ -161,6 +174,12 @@ public class FixedDepositProduct extends SavingsProduct {
|
||||
|
||||
actualChanges.putAll(super.update(command));
|
||||
|
||||
if (command.isChangeInStringParameterNamed("fdType", this.fdType)) {
|
||||
final String newValue = command.stringValueOfParameterNamed("fdType");
|
||||
actualChanges.put("fdType", newValue);
|
||||
this.fdType = (newValue != null && !newValue.isBlank()) ? newValue : null;
|
||||
}
|
||||
|
||||
if (this.productTermAndPreClosure != null) {
|
||||
actualChanges.putAll(this.productTermAndPreClosure.update(command, baseDataValidator));
|
||||
}
|
||||
|
||||
+4
@@ -1034,6 +1034,10 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
|
||||
return this.withdrawalFeeApplicableForTransfer;
|
||||
}
|
||||
|
||||
public void setWithdrawalFeeApplicableForTransfer(boolean withdrawalFeeApplicableForTransfer) {
|
||||
this.withdrawalFeeApplicableForTransfer = withdrawalFeeApplicableForTransfer;
|
||||
}
|
||||
|
||||
public boolean isAllowOverdraft() {
|
||||
return this.allowOverdraft;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user