update RD Prodcut code
This commit is contained in:
+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 final class RdInterestRateEffectiveData {
|
||||
|
||||
private final Long id;
|
||||
private final Long productId;
|
||||
private final String versionLabel;
|
||||
private final LocalDate effectiveFromDate;
|
||||
private final LocalDate effectiveToDate;
|
||||
private final Boolean isActive;
|
||||
private final String remarks;
|
||||
private final List<RdInterestRateSlabData> slabs;
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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 final class RdInterestRateSlabData {
|
||||
|
||||
private final Long id;
|
||||
private final Integer srNo;
|
||||
private final String description;
|
||||
private final Integer periodTypeEnum;
|
||||
private final String periodTypeLabel;
|
||||
private final Integer fromPeriod;
|
||||
private final Integer toPeriod;
|
||||
private final BigDecimal annualInterestRate;
|
||||
}
|
||||
+116
-6
@@ -65,10 +65,36 @@ public final class RecurringDepositProductData extends DepositProductData {
|
||||
private String accountType;
|
||||
private String customerSegment;
|
||||
private String productCode;
|
||||
private java.time.LocalDate effectiveDate;
|
||||
private java.time.LocalDate effectiveTo;
|
||||
private java.time.LocalDate endDate;
|
||||
private Boolean introducerRequired;
|
||||
private Boolean shareLinkingEnabled;
|
||||
private Boolean nominationFacility;
|
||||
private Boolean dormancyAlert;
|
||||
private Integer interestCalculateSelector;
|
||||
private String averagePeriod;
|
||||
private Boolean autoPost;
|
||||
private Integer frequencyFixDay;
|
||||
private java.time.LocalDate lastInterestDate;
|
||||
private Boolean enableLockinPeriod;
|
||||
private String balanceFrequency;
|
||||
private Boolean accountClosedZeroBalanceInDayClosing;
|
||||
private Boolean balanceSwapOption;
|
||||
private Boolean msme;
|
||||
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 withdrawalFeeForTransfers;
|
||||
|
||||
public void setInterestCalculationTypeOption(Collection<EnumOptionData> v) { this.interestCalculationTypeOption = v; }
|
||||
public void setPeriodFrequencyOptions(Collection<EnumOptionData> v) { this.periodFrequencyOptions = v; }
|
||||
@@ -78,10 +104,84 @@ public final class RecurringDepositProductData extends DepositProductData {
|
||||
public void setAccountType(String v) { this.accountType = v; }
|
||||
public void setCustomerSegment(String v) { this.customerSegment = v; }
|
||||
public void setProductCode(String v) { this.productCode = v; }
|
||||
public void setEffectiveDate(java.time.LocalDate v) { this.effectiveDate = v; }
|
||||
public void setEffectiveTo(java.time.LocalDate v) { this.effectiveTo = v; }
|
||||
public void setEndDate(java.time.LocalDate v) { this.endDate = 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 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(java.time.LocalDate v) { this.lastInterestDate = v; }
|
||||
public void setEnableLockinPeriod(Boolean v) { this.enableLockinPeriod = v; }
|
||||
public void setBalanceFrequency(String v) { this.balanceFrequency = v; }
|
||||
public void setAccountClosedZeroBalanceInDayClosing(Boolean v) { this.accountClosedZeroBalanceInDayClosing = v; }
|
||||
public void setBalanceSwapOption(Boolean v) { this.balanceSwapOption = v; }
|
||||
public void setMsme(Boolean v) { this.msme = 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 setWithdrawalFeeForTransfers(Boolean v) { this.withdrawalFeeForTransfers = v; }
|
||||
|
||||
/** Copy all CBS custom fields from source into this instance. */
|
||||
public void copyCbsFieldsFrom(final RecurringDepositProductData src) {
|
||||
if (src == null) return;
|
||||
this.accountType = src.accountType;
|
||||
this.customerSegment = src.customerSegment;
|
||||
this.productCode = src.productCode;
|
||||
this.effectiveDate = src.effectiveDate;
|
||||
this.effectiveTo = src.effectiveTo;
|
||||
this.endDate = src.endDate;
|
||||
this.introducerRequired = src.introducerRequired;
|
||||
this.shareLinkingEnabled = src.shareLinkingEnabled;
|
||||
this.nominationFacility = src.nominationFacility;
|
||||
this.dormancyAlert = src.dormancyAlert;
|
||||
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.balanceFrequency = src.balanceFrequency;
|
||||
this.accountClosedZeroBalanceInDayClosing = src.accountClosedZeroBalanceInDayClosing;
|
||||
this.balanceSwapOption = src.balanceSwapOption;
|
||||
this.msme = src.msme;
|
||||
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.withdrawalFeeForTransfers = src.withdrawalFeeForTransfers;
|
||||
// options
|
||||
this.interestCalculationTypeOption = src.interestCalculationTypeOption;
|
||||
this.periodFrequencyOptions = src.periodFrequencyOptions;
|
||||
this.yesNoOptions = src.yesNoOptions;
|
||||
this.accountTypeOptions = src.accountTypeOptions;
|
||||
this.customerSegmentOptions = src.customerSegmentOptions;
|
||||
}
|
||||
|
||||
public String getProductCode() {
|
||||
return productCode;
|
||||
}
|
||||
|
||||
public static RecurringDepositProductData template(final CurrencyData currency, final EnumOptionData interestCompoundingPeriodType,
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
@@ -146,7 +246,8 @@ public final class RecurringDepositProductData extends DepositProductData {
|
||||
|
||||
public static RecurringDepositProductData withCharges(final RecurringDepositProductData existingProduct,
|
||||
final Collection<ChargeData> charges) {
|
||||
return new RecurringDepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName,
|
||||
final RecurringDepositProductData result = new RecurringDepositProductData(existingProduct.id, existingProduct.name,
|
||||
existingProduct.shortName,
|
||||
existingProduct.description, existingProduct.currency, existingProduct.nominalAnnualInterestRate,
|
||||
existingProduct.interestCompoundingPeriodType, existingProduct.interestPostingPeriodType,
|
||||
existingProduct.interestCalculationType, existingProduct.interestCalculationDaysInYearType,
|
||||
@@ -166,6 +267,8 @@ public final class RecurringDepositProductData extends DepositProductData {
|
||||
existingProduct.isMandatoryDeposit, existingProduct.allowWithdrawal, existingProduct.adjustAdvanceTowardsFuturePayments,
|
||||
existingProduct.periodFrequencyTypeOptions, existingProduct.minDepositAmount, existingProduct.depositAmount,
|
||||
existingProduct.maxDepositAmount, existingProduct.withHoldTax, existingProduct.taxGroup, existingProduct.taxGroupOptions);
|
||||
result.copyCbsFieldsFrom(existingProduct);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,7 +290,8 @@ public final class RecurringDepositProductData extends DepositProductData {
|
||||
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions,
|
||||
final Collection<EnumOptionData> periodFrequencyTypeOptions, final Collection<TaxGroupData> taxGroupOptions) {
|
||||
|
||||
return new RecurringDepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName,
|
||||
final RecurringDepositProductData result = new RecurringDepositProductData(existingProduct.id, existingProduct.name,
|
||||
existingProduct.shortName,
|
||||
existingProduct.description, existingProduct.currency, existingProduct.nominalAnnualInterestRate,
|
||||
existingProduct.interestCompoundingPeriodType, existingProduct.interestPostingPeriodType,
|
||||
existingProduct.interestCalculationType, existingProduct.interestCalculationDaysInYearType,
|
||||
@@ -206,7 +310,8 @@ public final class RecurringDepositProductData extends DepositProductData {
|
||||
existingProduct.adjustAdvanceTowardsFuturePayments, periodFrequencyTypeOptions, existingProduct.minDepositAmount,
|
||||
existingProduct.depositAmount, existingProduct.maxDepositAmount, existingProduct.withHoldTax, existingProduct.taxGroup,
|
||||
taxGroupOptions);
|
||||
|
||||
result.copyCbsFieldsFrom(existingProduct);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static RecurringDepositProductData withAccountingDetails(final RecurringDepositProductData existingProduct,
|
||||
@@ -227,7 +332,8 @@ public final class RecurringDepositProductData extends DepositProductData {
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
final Collection<ChargeData> penaltyOptions = null;
|
||||
|
||||
return new RecurringDepositProductData(existingProduct.id, existingProduct.name, existingProduct.shortName,
|
||||
final RecurringDepositProductData result = new RecurringDepositProductData(existingProduct.id, existingProduct.name,
|
||||
existingProduct.shortName,
|
||||
existingProduct.description, existingProduct.currency, existingProduct.nominalAnnualInterestRate,
|
||||
existingProduct.interestCompoundingPeriodType, existingProduct.interestPostingPeriodType,
|
||||
existingProduct.interestCalculationType, existingProduct.interestCalculationDaysInYearType,
|
||||
@@ -245,6 +351,8 @@ public final class RecurringDepositProductData extends DepositProductData {
|
||||
existingProduct.adjustAdvanceTowardsFuturePayments, existingProduct.periodFrequencyTypeOptions,
|
||||
existingProduct.minDepositAmount, existingProduct.depositAmount, existingProduct.maxDepositAmount,
|
||||
existingProduct.withHoldTax, existingProduct.taxGroup, existingProduct.taxGroupOptions);
|
||||
result.copyCbsFieldsFrom(existingProduct);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static RecurringDepositProductData instance(final DepositProductData depositProductData, final boolean preClosurePenalApplicable,
|
||||
@@ -367,7 +475,8 @@ public final class RecurringDepositProductData extends DepositProductData {
|
||||
|
||||
public static RecurringDepositProductData withInterestChart(final RecurringDepositProductData product,
|
||||
final Collection<InterestRateChartData> interestRateCharts) {
|
||||
return new RecurringDepositProductData(product.id, product.name, product.shortName, product.description, product.currency,
|
||||
final RecurringDepositProductData result = new RecurringDepositProductData(product.id, product.name, product.shortName,
|
||||
product.description, product.currency,
|
||||
product.nominalAnnualInterestRate, product.interestCompoundingPeriodType, product.interestPostingPeriodType,
|
||||
product.interestCalculationType, product.interestCalculationDaysInYearType, product.lockinPeriodFrequency,
|
||||
product.lockinPeriodFrequencyType, product.minBalanceForInterestCalculation, product.accountingRule,
|
||||
@@ -383,7 +492,8 @@ public final class RecurringDepositProductData extends DepositProductData {
|
||||
product.inMultiplesOfDepositTermType, product.isMandatoryDeposit, product.allowWithdrawal,
|
||||
product.adjustAdvanceTowardsFuturePayments, product.periodFrequencyTypeOptions, product.minDepositAmount,
|
||||
product.depositAmount, product.maxDepositAmount, product.withHoldTax, product.taxGroup, product.taxGroupOptions);
|
||||
|
||||
result.copyCbsFieldsFrom(product);
|
||||
return result;
|
||||
}
|
||||
|
||||
private RecurringDepositProductData(final Long id, final String name, final String shortName, final String description,
|
||||
|
||||
+69
@@ -58,9 +58,13 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withHold
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.accounting.common.AccountingRuleType;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
@@ -277,6 +281,47 @@ public class DepositProductAssembler {
|
||||
productTermAndPreClosure.updateProductReference(recurringDepositProduct);
|
||||
productRecurringDetail.updateProductReference(recurringDepositProduct);
|
||||
|
||||
// ── CBS Custom Fields (from 0251 migration) ─────────────────────────
|
||||
recurringDepositProduct.setAccountType(command.stringValueOfParameterNamed("accountType"));
|
||||
recurringDepositProduct.setCustomerSegment(command.stringValueOfParameterNamed("customerSegment"));
|
||||
recurringDepositProduct.setProductCode(command.stringValueOfParameterNamed("productCode"));
|
||||
recurringDepositProduct.setEffectiveDate(parseCbsDate(command.stringValueOfParameterNamed("effectiveDate")));
|
||||
recurringDepositProduct.setEffectiveTo(parseCbsDate(command.stringValueOfParameterNamed("effectiveTo")));
|
||||
recurringDepositProduct.setEndDate(parseCbsDate(command.stringValueOfParameterNamed("endDate")));
|
||||
recurringDepositProduct.setIntroducerRequired(command.booleanPrimitiveValueOfParameterNamed("introducerRequired"));
|
||||
recurringDepositProduct.setShareLinkingEnabled(command.booleanPrimitiveValueOfParameterNamed("shareLinkingEnabled"));
|
||||
recurringDepositProduct.setNominationFacility(command.booleanPrimitiveValueOfParameterNamed("nominationFacility"));
|
||||
recurringDepositProduct.setDormancyAlert(command.booleanPrimitiveValueOfParameterNamed("dormancyAlert"));
|
||||
recurringDepositProduct.setInterestCalculateSelector(command.integerValueOfParameterNamed("interestCalculateSelector"));
|
||||
recurringDepositProduct.setAveragePeriod(command.stringValueOfParameterNamed("averagePeriod"));
|
||||
recurringDepositProduct.setAutoPost(command.booleanPrimitiveValueOfParameterNamed("autoPost"));
|
||||
recurringDepositProduct.setFrequencyFixDay(command.integerValueOfParameterNamed("frequencyFixDay"));
|
||||
recurringDepositProduct.setLastInterestDate(parseCbsDate(command.stringValueOfParameterNamed("lastInterestDate")));
|
||||
recurringDepositProduct.setEnableLockinPeriod(command.booleanPrimitiveValueOfParameterNamed("enableLockinPeriod"));
|
||||
recurringDepositProduct.setBalanceFrequency(command.stringValueOfParameterNamed("balanceFrequency"));
|
||||
if (command.parameterExists("accountClosedZeroBalanceInDayClosing")) {
|
||||
recurringDepositProduct.setAccountClosedZeroBalanceInDayClosing(
|
||||
command.booleanPrimitiveValueOfParameterNamed("accountClosedZeroBalanceInDayClosing"));
|
||||
}
|
||||
|
||||
// ── RD-specific flags (from 0270 migration) ──────────────────────────
|
||||
recurringDepositProduct.setBalanceSwapOption(command.booleanPrimitiveValueOfParameterNamed("balanceSwapOption"));
|
||||
recurringDepositProduct.setMsme(command.booleanPrimitiveValueOfParameterNamed("msme"));
|
||||
recurringDepositProduct.setAutoDebitFacility(command.booleanPrimitiveValueOfParameterNamed("autoDebitFacility"));
|
||||
recurringDepositProduct.setLoanFacility(command.booleanPrimitiveValueOfParameterNamed("loanFacility"));
|
||||
recurringDepositProduct.setPrematureWithdrawalOption(command.booleanPrimitiveValueOfParameterNamed("prematureWithdrawalOption"));
|
||||
recurringDepositProduct.setTenureFlexibility(command.booleanPrimitiveValueOfParameterNamed("tenureFlexibility"));
|
||||
recurringDepositProduct.setLienMarked(command.booleanPrimitiveValueOfParameterNamed("lienMarked"));
|
||||
recurringDepositProduct.setMaturityInstructions(command.booleanPrimitiveValueOfParameterNamed("maturityInstructions"));
|
||||
recurringDepositProduct.setCreditMaturityProceeds(command.booleanPrimitiveValueOfParameterNamed("creditMaturityProceeds"));
|
||||
recurringDepositProduct.setPenaltyGracePeriodMissedInstallments(
|
||||
command.booleanPrimitiveValueOfParameterNamed("penaltyGracePeriodMissedInstallments"));
|
||||
recurringDepositProduct.setPanelRequestApplicable(command.booleanPrimitiveValueOfParameterNamed("panelRequestApplicable"));
|
||||
recurringDepositProduct.setNoPenaltyNomineeHeirClosure(
|
||||
command.booleanPrimitiveValueOfParameterNamed("noPenaltyNomineeHeirClosure"));
|
||||
recurringDepositProduct.setDeceasedSettlement(command.booleanPrimitiveValueOfParameterNamed("deceasedSettlement"));
|
||||
recurringDepositProduct.setAllowDebitTxnAfterDueDate(command.booleanPrimitiveValueOfParameterNamed("allowDebitTxnAfterDueDate"));
|
||||
|
||||
recurringDepositProduct.validateDomainRules();
|
||||
|
||||
return recurringDepositProduct;
|
||||
@@ -500,6 +545,30 @@ public class DepositProductAssembler {
|
||||
return new DepositProductAmountDetails(minDepositAmount, depositAmount, maxDepositAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a CBS date string using common formats (e.g. "17 April 2026", "2026-04-17").
|
||||
* Returns null if the input is null or blank.
|
||||
*/
|
||||
private LocalDate parseCbsDate(final String dateStr) {
|
||||
if (dateStr == null || dateStr.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
DateTimeFormatter[] formatters = {
|
||||
DateTimeFormatter.ofPattern("dd MMMM yyyy", Locale.ENGLISH),
|
||||
DateTimeFormatter.ofPattern("dd MMM yyyy", Locale.ENGLISH),
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.ENGLISH),
|
||||
DateTimeFormatter.ofPattern("dd/MM/yyyy", Locale.ENGLISH)
|
||||
};
|
||||
for (DateTimeFormatter fmt : formatters) {
|
||||
try {
|
||||
return LocalDate.parse(dateStr, fmt);
|
||||
} catch (DateTimeParseException ignored) {
|
||||
// try next format
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public TaxGroup assembleTaxGroup(final JsonCommand command) {
|
||||
final Long taxGroupId = command.longValueOfParameterNamed(taxGroupIdParamName);
|
||||
TaxGroup taxGroup = null;
|
||||
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* 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;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_rd_interest_rate_effective")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class RdInterestRateEffective {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "product_id", nullable = false)
|
||||
private Long productId;
|
||||
|
||||
@Column(name = "version_label", nullable = false, length = 100)
|
||||
private String versionLabel;
|
||||
|
||||
@Column(name = "effective_from_date", nullable = false)
|
||||
private LocalDate effectiveFromDate;
|
||||
|
||||
@Column(name = "effective_to_date")
|
||||
private LocalDate effectiveToDate;
|
||||
|
||||
@Column(name = "is_active", nullable = false)
|
||||
private Boolean isActive;
|
||||
|
||||
@Column(name = "remarks", length = 500)
|
||||
private String remarks;
|
||||
|
||||
@Column(name = "created_by_id")
|
||||
private Long createdById;
|
||||
|
||||
@Column(name = "created_date")
|
||||
private LocalDate createdDate;
|
||||
|
||||
public static RdInterestRateEffective create(Long productId, String versionLabel,
|
||||
LocalDate effectiveFromDate, String remarks, Long createdById) {
|
||||
RdInterestRateEffective e = new RdInterestRateEffective();
|
||||
e.productId = productId;
|
||||
e.versionLabel = versionLabel;
|
||||
e.effectiveFromDate = effectiveFromDate;
|
||||
e.isActive = true;
|
||||
e.remarks = remarks;
|
||||
e.createdById = createdById;
|
||||
e.createdDate = LocalDate.now();
|
||||
return e;
|
||||
}
|
||||
}
|
||||
+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.domain;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface RdInterestRateEffectiveRepository extends JpaRepository<RdInterestRateEffective, Long> {
|
||||
|
||||
List<RdInterestRateEffective> findByProductIdOrderByEffectiveFromDateDesc(Long productId);
|
||||
|
||||
List<RdInterestRateEffective> findByIsActiveTrueOrderByEffectiveFromDateDesc();
|
||||
|
||||
@Modifying
|
||||
@Query("UPDATE RdInterestRateEffective e SET e.isActive = false WHERE e.productId = :productId AND e.isActive = true")
|
||||
void deactivateAllForProduct(@Param("productId") Long productId);
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* 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_rd_interest_rate_slab_history")
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class RdInterestRateSlabHistory {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "effective_id", nullable = false)
|
||||
private Long effectiveId;
|
||||
|
||||
@Column(name = "sr_no", nullable = false)
|
||||
private Integer srNo;
|
||||
|
||||
@Column(name = "description", length = 200)
|
||||
private String description;
|
||||
|
||||
@Column(name = "period_type_enum", nullable = false)
|
||||
private Integer periodTypeEnum;
|
||||
|
||||
@Column(name = "from_period", nullable = false)
|
||||
private Integer fromPeriod;
|
||||
|
||||
@Column(name = "to_period")
|
||||
private Integer toPeriod;
|
||||
|
||||
@Column(name = "annual_interest_rate", nullable = false, precision = 19, scale = 6)
|
||||
private BigDecimal annualInterestRate;
|
||||
|
||||
@Column(name = "created_date")
|
||||
private LocalDate createdDate;
|
||||
|
||||
public static RdInterestRateSlabHistory create(Long effectiveId, Integer srNo, String description,
|
||||
Integer periodTypeEnum, Integer fromPeriod, Integer toPeriod, BigDecimal annualInterestRate) {
|
||||
RdInterestRateSlabHistory s = new RdInterestRateSlabHistory();
|
||||
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.createdDate = LocalDate.now();
|
||||
return s;
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface RdInterestRateSlabHistoryRepository extends JpaRepository<RdInterestRateSlabHistory, Long> {
|
||||
|
||||
List<RdInterestRateSlabHistory> findByEffectiveIdOrderBySrNo(Long effectiveId);
|
||||
}
|
||||
+10
-6
@@ -150,12 +150,16 @@ public class RecurringDepositProduct extends FixedDepositProduct {
|
||||
}
|
||||
|
||||
private void validateDomainRules(final DataValidatorBuilder baseDataValidator) {
|
||||
final DepositTermDetail termDetails = this.depositProductTermAndPreClosure().depositTermDetail();
|
||||
final boolean isMinTermGreaterThanMax = termDetails.isMinDepositTermGreaterThanMaxDepositTerm();
|
||||
if (isMinTermGreaterThanMax) {
|
||||
final Integer maxTerm = termDetails.maxDepositTerm();
|
||||
baseDataValidator.reset().parameter(maxDepositTermParamName).value(maxTerm)
|
||||
.failWithCodeNoParameterAddedToErrorCode("max.term.lessthan.min.term");
|
||||
final DepositTermDetail termDetails = this.depositProductTermAndPreClosure() != null
|
||||
? this.depositProductTermAndPreClosure().depositTermDetail()
|
||||
: null;
|
||||
if (termDetails != null) {
|
||||
final boolean isMinTermGreaterThanMax = termDetails.isMinDepositTermGreaterThanMaxDepositTerm();
|
||||
if (isMinTermGreaterThanMax) {
|
||||
final Integer maxTerm = termDetails.maxDepositTerm();
|
||||
baseDataValidator.reset().parameter(maxDepositTermParamName).value(maxTerm)
|
||||
.failWithCodeNoParameterAddedToErrorCode("max.term.lessthan.min.term");
|
||||
}
|
||||
}
|
||||
|
||||
if (this.charts != null) {
|
||||
|
||||
+191
-16
@@ -90,6 +90,9 @@ import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -290,6 +293,49 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
|
||||
@Column(name = "account_closed_zero_balance_in_day_closing")
|
||||
private Boolean accountClosedZeroBalanceInDayClosing = false;
|
||||
|
||||
// RD-specific flags
|
||||
@Column(name = "balance_swap_option")
|
||||
private boolean balanceSwapOption = false;
|
||||
|
||||
@Column(name = "msme")
|
||||
private boolean msme = false;
|
||||
|
||||
@Column(name = "auto_debit_facility")
|
||||
private boolean autoDebitFacility = false;
|
||||
|
||||
@Column(name = "loan_facility")
|
||||
private boolean loanFacility = false;
|
||||
|
||||
@Column(name = "premature_withdrawal_option")
|
||||
private boolean prematureWithdrawalOption = false;
|
||||
|
||||
@Column(name = "tenure_flexibility")
|
||||
private boolean tenureFlexibility = false;
|
||||
|
||||
@Column(name = "lien_marked")
|
||||
private boolean lienMarked = false;
|
||||
|
||||
@Column(name = "maturity_instructions")
|
||||
private boolean maturityInstructions = false;
|
||||
|
||||
@Column(name = "credit_maturity_proceeds")
|
||||
private boolean creditMaturityProceeds = false;
|
||||
|
||||
@Column(name = "penalty_grace_period_missed_installments")
|
||||
private boolean penaltyGracePeriodMissedInstallments = false;
|
||||
|
||||
@Column(name = "panel_request_applicable")
|
||||
private boolean panelRequestApplicable = false;
|
||||
|
||||
@Column(name = "no_penalty_nominee_heir_closure")
|
||||
private boolean noPenaltyNomineeHeirClosure = false;
|
||||
|
||||
@Column(name = "deceased_settlement")
|
||||
private boolean deceasedSettlement = false;
|
||||
|
||||
@Column(name = "allow_debit_txn_after_due_date")
|
||||
private boolean allowDebitTxnAfterDueDate = false;
|
||||
|
||||
// Relationships for complex objects
|
||||
@OneToOne(cascade = CascadeType.ALL, mappedBy = "savingsProduct", orphanRemoval = true)
|
||||
private SavingsProductFacilityConfig facilityConfig;
|
||||
@@ -750,20 +796,26 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
|
||||
actualChanges.put(productCodeParamName, newValue);
|
||||
this.productCode = newValue;
|
||||
}
|
||||
if (command.isChangeInLocalDateParameterNamed(effectiveDateParamName, this.effectiveDate)) {
|
||||
final LocalDate newValue = command.localDateValueOfParameterNamed(effectiveDateParamName);
|
||||
actualChanges.put(effectiveDateParamName, newValue);
|
||||
this.effectiveDate = newValue;
|
||||
if (command.parameterExists(effectiveDateParamName)) {
|
||||
final LocalDate newValue = parseCbsLocalDate(command.stringValueOfParameterNamed(effectiveDateParamName));
|
||||
if (!Objects.equals(newValue, this.effectiveDate)) {
|
||||
actualChanges.put(effectiveDateParamName, newValue);
|
||||
this.effectiveDate = newValue;
|
||||
}
|
||||
}
|
||||
if (command.isChangeInLocalDateParameterNamed(effectiveToParamName, this.effectiveTo)) {
|
||||
final LocalDate newValue = command.localDateValueOfParameterNamed(effectiveToParamName);
|
||||
actualChanges.put(effectiveToParamName, newValue);
|
||||
this.effectiveTo = newValue;
|
||||
if (command.parameterExists(effectiveToParamName)) {
|
||||
final LocalDate newValue = parseCbsLocalDate(command.stringValueOfParameterNamed(effectiveToParamName));
|
||||
if (!Objects.equals(newValue, this.effectiveTo)) {
|
||||
actualChanges.put(effectiveToParamName, newValue);
|
||||
this.effectiveTo = newValue;
|
||||
}
|
||||
}
|
||||
if (command.isChangeInLocalDateParameterNamed(endDateParamName, this.endDate)) {
|
||||
final LocalDate newValue = command.localDateValueOfParameterNamed(endDateParamName);
|
||||
actualChanges.put(endDateParamName, newValue);
|
||||
this.endDate = newValue;
|
||||
if (command.parameterExists(endDateParamName)) {
|
||||
final LocalDate newValue = parseCbsLocalDate(command.stringValueOfParameterNamed(endDateParamName));
|
||||
if (!Objects.equals(newValue, this.endDate)) {
|
||||
actualChanges.put(endDateParamName, newValue);
|
||||
this.endDate = newValue;
|
||||
}
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed(introducerRequiredParamName, this.introducerRequired)) {
|
||||
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(introducerRequiredParamName);
|
||||
@@ -805,10 +857,12 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
|
||||
actualChanges.put(frequencyFixDayParamName, newValue);
|
||||
this.frequencyFixDay = newValue;
|
||||
}
|
||||
if (command.isChangeInLocalDateParameterNamed(lastInterestDateParamName, this.lastInterestDate)) {
|
||||
final LocalDate newValue = command.localDateValueOfParameterNamed(lastInterestDateParamName);
|
||||
actualChanges.put(lastInterestDateParamName, newValue);
|
||||
this.lastInterestDate = newValue;
|
||||
if (command.parameterExists(lastInterestDateParamName)) {
|
||||
final LocalDate newValue = parseCbsLocalDate(command.stringValueOfParameterNamed(lastInterestDateParamName));
|
||||
if (!Objects.equals(newValue, this.lastInterestDate)) {
|
||||
actualChanges.put(lastInterestDateParamName, newValue);
|
||||
this.lastInterestDate = newValue;
|
||||
}
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed(enableLockinPeriodParamName, this.enableLockinPeriod)) {
|
||||
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(enableLockinPeriodParamName);
|
||||
@@ -830,6 +884,64 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
|
||||
this.accountClosedZeroBalanceInDayClosing = newValue;
|
||||
}
|
||||
|
||||
// Update RD-specific flags (0270 migration fields)
|
||||
if (command.isChangeInBooleanParameterNamed("balanceSwapOption", this.balanceSwapOption)) {
|
||||
this.balanceSwapOption = command.booleanPrimitiveValueOfParameterNamed("balanceSwapOption");
|
||||
actualChanges.put("balanceSwapOption", this.balanceSwapOption);
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed("msme", this.msme)) {
|
||||
this.msme = command.booleanPrimitiveValueOfParameterNamed("msme");
|
||||
actualChanges.put("msme", this.msme);
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed("autoDebitFacility", this.autoDebitFacility)) {
|
||||
this.autoDebitFacility = command.booleanPrimitiveValueOfParameterNamed("autoDebitFacility");
|
||||
actualChanges.put("autoDebitFacility", this.autoDebitFacility);
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed("loanFacility", this.loanFacility)) {
|
||||
this.loanFacility = command.booleanPrimitiveValueOfParameterNamed("loanFacility");
|
||||
actualChanges.put("loanFacility", this.loanFacility);
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed("prematureWithdrawalOption", this.prematureWithdrawalOption)) {
|
||||
this.prematureWithdrawalOption = command.booleanPrimitiveValueOfParameterNamed("prematureWithdrawalOption");
|
||||
actualChanges.put("prematureWithdrawalOption", this.prematureWithdrawalOption);
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed("tenureFlexibility", this.tenureFlexibility)) {
|
||||
this.tenureFlexibility = command.booleanPrimitiveValueOfParameterNamed("tenureFlexibility");
|
||||
actualChanges.put("tenureFlexibility", this.tenureFlexibility);
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed("lienMarked", this.lienMarked)) {
|
||||
this.lienMarked = command.booleanPrimitiveValueOfParameterNamed("lienMarked");
|
||||
actualChanges.put("lienMarked", this.lienMarked);
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed("maturityInstructions", this.maturityInstructions)) {
|
||||
this.maturityInstructions = command.booleanPrimitiveValueOfParameterNamed("maturityInstructions");
|
||||
actualChanges.put("maturityInstructions", this.maturityInstructions);
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed("creditMaturityProceeds", this.creditMaturityProceeds)) {
|
||||
this.creditMaturityProceeds = command.booleanPrimitiveValueOfParameterNamed("creditMaturityProceeds");
|
||||
actualChanges.put("creditMaturityProceeds", this.creditMaturityProceeds);
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed("penaltyGracePeriodMissedInstallments", this.penaltyGracePeriodMissedInstallments)) {
|
||||
this.penaltyGracePeriodMissedInstallments = command.booleanPrimitiveValueOfParameterNamed("penaltyGracePeriodMissedInstallments");
|
||||
actualChanges.put("penaltyGracePeriodMissedInstallments", this.penaltyGracePeriodMissedInstallments);
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed("panelRequestApplicable", this.panelRequestApplicable)) {
|
||||
this.panelRequestApplicable = command.booleanPrimitiveValueOfParameterNamed("panelRequestApplicable");
|
||||
actualChanges.put("panelRequestApplicable", this.panelRequestApplicable);
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed("noPenaltyNomineeHeirClosure", this.noPenaltyNomineeHeirClosure)) {
|
||||
this.noPenaltyNomineeHeirClosure = command.booleanPrimitiveValueOfParameterNamed("noPenaltyNomineeHeirClosure");
|
||||
actualChanges.put("noPenaltyNomineeHeirClosure", this.noPenaltyNomineeHeirClosure);
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed("deceasedSettlement", this.deceasedSettlement)) {
|
||||
this.deceasedSettlement = command.booleanPrimitiveValueOfParameterNamed("deceasedSettlement");
|
||||
actualChanges.put("deceasedSettlement", this.deceasedSettlement);
|
||||
}
|
||||
if (command.isChangeInBooleanParameterNamed("allowDebitTxnAfterDueDate", this.allowDebitTxnAfterDueDate)) {
|
||||
this.allowDebitTxnAfterDueDate = command.booleanPrimitiveValueOfParameterNamed("allowDebitTxnAfterDueDate");
|
||||
actualChanges.put("allowDebitTxnAfterDueDate", this.allowDebitTxnAfterDueDate);
|
||||
}
|
||||
|
||||
validateLockinDetails();
|
||||
esnureOverdraftLimitsSetForOverdraftAccounts();
|
||||
|
||||
@@ -1142,6 +1254,48 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
|
||||
this.accountClosedZeroBalanceInDayClosing = accountClosedZeroBalanceInDayClosing;
|
||||
}
|
||||
|
||||
public boolean isBalanceSwapOption() { return balanceSwapOption; }
|
||||
public void setBalanceSwapOption(boolean v) { this.balanceSwapOption = v; }
|
||||
|
||||
public boolean isMsme() { return msme; }
|
||||
public void setMsme(boolean v) { this.msme = v; }
|
||||
|
||||
public boolean isAutoDebitFacility() { return autoDebitFacility; }
|
||||
public void setAutoDebitFacility(boolean v) { this.autoDebitFacility = v; }
|
||||
|
||||
public boolean isLoanFacility() { return loanFacility; }
|
||||
public void setLoanFacility(boolean v) { this.loanFacility = v; }
|
||||
|
||||
public boolean isPrematureWithdrawalOption() { return prematureWithdrawalOption; }
|
||||
public void setPrematureWithdrawalOption(boolean v) { this.prematureWithdrawalOption = v; }
|
||||
|
||||
public boolean isTenureFlexibility() { return tenureFlexibility; }
|
||||
public void setTenureFlexibility(boolean v) { this.tenureFlexibility = v; }
|
||||
|
||||
public boolean isLienMarked() { return lienMarked; }
|
||||
public void setLienMarked(boolean v) { this.lienMarked = v; }
|
||||
|
||||
public boolean isMaturityInstructions() { return maturityInstructions; }
|
||||
public void setMaturityInstructions(boolean v) { this.maturityInstructions = v; }
|
||||
|
||||
public boolean isCreditMaturityProceeds() { return creditMaturityProceeds; }
|
||||
public void setCreditMaturityProceeds(boolean v) { this.creditMaturityProceeds = v; }
|
||||
|
||||
public boolean isPenaltyGracePeriodMissedInstallments() { return penaltyGracePeriodMissedInstallments; }
|
||||
public void setPenaltyGracePeriodMissedInstallments(boolean v) { this.penaltyGracePeriodMissedInstallments = v; }
|
||||
|
||||
public boolean isPanelRequestApplicable() { return panelRequestApplicable; }
|
||||
public void setPanelRequestApplicable(boolean v) { this.panelRequestApplicable = v; }
|
||||
|
||||
public boolean isNoPenaltyNomineeHeirClosure() { return noPenaltyNomineeHeirClosure; }
|
||||
public void setNoPenaltyNomineeHeirClosure(boolean v) { this.noPenaltyNomineeHeirClosure = v; }
|
||||
|
||||
public boolean isDeceasedSettlement() { return deceasedSettlement; }
|
||||
public void setDeceasedSettlement(boolean v) { this.deceasedSettlement = v; }
|
||||
|
||||
public boolean isAllowDebitTxnAfterDueDate() { return allowDebitTxnAfterDueDate; }
|
||||
public void setAllowDebitTxnAfterDueDate(boolean v) { this.allowDebitTxnAfterDueDate = v; }
|
||||
|
||||
public SavingsProductFacilityConfig getFacilityConfig() {
|
||||
return facilityConfig;
|
||||
}
|
||||
@@ -1174,4 +1328,25 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses CBS date strings (e.g. "17 April 2026") without requiring a dateFormat parameter.
|
||||
*/
|
||||
public static LocalDate parseCbsLocalDate(final String dateStr) {
|
||||
if (dateStr == null || dateStr.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
for (DateTimeFormatter fmt : Arrays.asList(
|
||||
DateTimeFormatter.ofPattern("dd MMMM yyyy", java.util.Locale.ENGLISH),
|
||||
DateTimeFormatter.ofPattern("dd MMM yyyy", java.util.Locale.ENGLISH),
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd", java.util.Locale.ENGLISH),
|
||||
DateTimeFormatter.ofPattern("dd/MM/yyyy", java.util.Locale.ENGLISH))) {
|
||||
try {
|
||||
return LocalDate.parse(dateStr, fmt);
|
||||
} catch (DateTimeParseException ignored) {
|
||||
// try next
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user