feat: update savings product backend changes

This commit is contained in:
Nitesh Yadav
2026-04-28 13:12:27 +05:30
parent 72adbf6305
commit dc4a720ae2
16 changed files with 17339 additions and 35 deletions
@@ -88,7 +88,13 @@ public class SavingsApiSetConstants extends SavingsApiConstants {
"interestCalculateSelector", "averagePeriod", "autoPost", "frequencyFixDay", "lastInterestDate",
"balanceSwapOption", "msme", "autoDebitFacility", "interestCalculationTypeOption",
"effectiveDate", "isDormancyTrackingActive", "daysToInactive", "daysToDormancy", "daysToEscheat",
"avgBalanceCalcPeriod", "validForPeriod", "odAccountClosedZeroBalanceInDayClosing"));
"avgBalanceCalcPeriod", "validForPeriod", "odAccountClosedZeroBalanceInDayClosing",
// CBS Account fields
"cbsAccountType", "accountStatus", "modeOfOperation", "specialCategory", "weakerSection",
"guardianName", "guardianCifNumber", "guardianRelationship", "guardianClientId", "minorDateOfBirth",
"introducerClientId", "introducerName", "introducerCifNumber",
"nomineeData", "linkedAccountId", "linkedAccountType", "linkedAccountNo",
"jointHolders"));
protected static final Set<String> SAVINGS_TRANSACTION_RESPONSE_DATA_PARAMETERS = new HashSet<>(
Arrays.asList(idParamName, "accountId", accountNoParamName, "currency", "amount", dateParamName, paymentDetailDataParamName,
@@ -39,7 +39,15 @@ public class SavingsAccountConstant extends SavingsApiConstants {
withdrawalFeeForTransfersParamName, feeAmountParamName, feeOnMonthDayParamName, chargesParamName, allowOverdraftParamName,
overdraftLimitParamName, minRequiredBalanceParamName, enforceMinRequiredBalanceParamName, lienAllowedParamName,
maxAllowedLienLimitParamName, nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName,
withHoldTaxParamName, datatables, gsimApplicationId, gsimLastApplication));
withHoldTaxParamName, datatables, gsimApplicationId, gsimLastApplication,
// CBS Account fields
"accountType", "customerSegment", accountStatusParamName, modeOfOperationParamName,
specialCategoryParamName, weakerSectionParamName,
guardianNameParamName, guardianCifNumberParamName, guardianRelationshipParamName,
guardianClientIdParamName, minorDateOfBirthParamName,
introducerIdParamName, introducerNameParamName, introducerCifNumberParamName,
nomineeParamName, linkedAccountIdParamName, linkedAccountTypeParamName, linkedAccountNoParamName,
accountFacilityConfigParamName, jointHoldersParamName));
/**
* These parameters will match the class level parameters of {@link SavingsAccountData}. Where possible, we try to
@@ -3900,4 +3900,126 @@ public class SavingsAccount extends AbstractAuditableWithUTCDateTimeCustom<Long>
public DepositAccountType depositAccountType() {
return DepositAccountType.fromInt(100);
}
// ─── CBS extended fields ───────────────────────────────────────────────────
@Column(name = "cbs_account_type", length = 100)
private String cbsAccountType;
@Column(name = "customer_segment", length = 100)
private String customerSegment;
@Column(name = "account_status", length = 50)
private String accountStatus;
@Column(name = "mode_of_operation", length = 50)
private String modeOfOperation;
@Column(name = "special_category", length = 100)
private String specialCategory;
@Column(name = "weaker_section", length = 100)
private String weakerSection;
@Column(name = "guardian_name", length = 200)
private String guardianName;
@Column(name = "guardian_cif_number", length = 50)
private String guardianCifNumber;
@Column(name = "guardian_relationship", length = 100)
private String guardianRelationship;
@Column(name = "minor_date_of_birth")
private LocalDate minorDateOfBirth;
@Column(name = "guardian_client_id")
private Long guardianClientId;
@Column(name = "introducer_client_id")
private Long introducerClientId;
@Column(name = "introducer_name", length = 200)
private String introducerName;
@Column(name = "introducer_cif_number", length = 50)
private String introducerCifNumber;
@Column(name = "nominee_data", columnDefinition = "TEXT")
private String nomineeData;
@Column(name = "linked_account_id")
private Long linkedAccountId;
@Column(name = "linked_account_type", length = 20)
private String linkedAccountType;
@Column(name = "linked_account_no", length = 50)
private String linkedAccountNo;
@jakarta.persistence.OneToOne(cascade = jakarta.persistence.CascadeType.ALL, mappedBy = "savingsAccount", orphanRemoval = true, fetch = FetchType.LAZY)
private SavingsAccountFacilityConfig facilityConfig;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "savingsAccount", orphanRemoval = true, fetch = FetchType.LAZY)
private List<SavingsAccountJointHolder> jointHolders = new ArrayList<>();
public String getCbsAccountType() { return cbsAccountType; }
public void setCbsAccountType(String v) { this.cbsAccountType = v; }
public String getCustomerSegment() { return customerSegment; }
public void setCustomerSegment(String v) { this.customerSegment = v; }
public String getAccountStatus() { return accountStatus; }
public void setAccountStatus(String v) { this.accountStatus = v; }
public String getModeOfOperation() { return modeOfOperation; }
public void setModeOfOperation(String v) { this.modeOfOperation = v; }
public String getSpecialCategory() { return specialCategory; }
public void setSpecialCategory(String v) { this.specialCategory = v; }
public String getWeakerSection() { return weakerSection; }
public void setWeakerSection(String v) { this.weakerSection = v; }
public String getGuardianName() { return guardianName; }
public void setGuardianName(String v) { this.guardianName = v; }
public String getGuardianCifNumber() { return guardianCifNumber; }
public void setGuardianCifNumber(String v) { this.guardianCifNumber = v; }
public String getGuardianRelationship() { return guardianRelationship; }
public void setGuardianRelationship(String v) { this.guardianRelationship = v; }
public LocalDate getMinorDateOfBirth() { return minorDateOfBirth; }
public void setMinorDateOfBirth(LocalDate v) { this.minorDateOfBirth = v; }
public Long getGuardianClientId() { return guardianClientId; }
public void setGuardianClientId(Long v) { this.guardianClientId = v; }
public Long getIntroducerClientId() { return introducerClientId; }
public void setIntroducerClientId(Long v) { this.introducerClientId = v; }
public String getIntroducerName() { return introducerName; }
public void setIntroducerName(String v) { this.introducerName = v; }
public String getIntroducerCifNumber() { return introducerCifNumber; }
public void setIntroducerCifNumber(String v) { this.introducerCifNumber = v; }
public String getNomineeData() { return nomineeData; }
public void setNomineeData(String v) { this.nomineeData = v; }
public Long getLinkedAccountId() { return linkedAccountId; }
public void setLinkedAccountId(Long v) { this.linkedAccountId = v; }
public String getLinkedAccountType() { return linkedAccountType; }
public void setLinkedAccountType(String v) { this.linkedAccountType = v; }
public String getLinkedAccountNo() { return linkedAccountNo; }
public void setLinkedAccountNo(String v) { this.linkedAccountNo = v; }
public SavingsAccountFacilityConfig getFacilityConfig() { return facilityConfig; }
public void setFacilityConfig(SavingsAccountFacilityConfig v) { this.facilityConfig = v; }
public List<SavingsAccountJointHolder> getJointHolders() { return jointHolders; }
public void setJointHolders(List<SavingsAccountJointHolder> v) { this.jointHolders = v; }
}
@@ -0,0 +1,168 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.savings.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import java.time.LocalDateTime;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity
@Table(name = "m_savings_account_facility_config")
public class SavingsAccountFacilityConfig extends AbstractPersistableCustom<Long> {
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "savings_account_id", nullable = false)
private SavingsAccount savingsAccount;
@Column(name = "atm_facility")
private Boolean atmFacility = false;
@Column(name = "atm_withdrawal_facility")
private Boolean atmWithdrawalFacility = false;
@Column(name = "upi_facility")
private Boolean upiFacility = false;
@Column(name = "pos_transactions_facility")
private Boolean posTransactionsFacility = false;
@Column(name = "cheque_book")
private Boolean chequeBook = false;
@Column(name = "imps_facility")
private Boolean impsFacility = false;
@Column(name = "sms_alerts")
private Boolean smsAlerts = false;
@Column(name = "bbps_facility")
private Boolean bbpsFacility = false;
@Column(name = "insurance_cover")
private Boolean insuranceCover = false;
@Column(name = "bepg_facility")
private Boolean bepgFacility = false;
@Column(name = "neft_facility")
private Boolean neftFacility = false;
@Column(name = "rtgs_facility")
private Boolean rtgsFacility = false;
@Column(name = "inter_bank_total_cap_facility")
private Boolean interBankTotalCapFacility = false;
@Column(name = "withdrawal_facility")
private Boolean withdrawalFacility = false;
@Column(name = "deposit_facility_kyc")
private Boolean depositFacilityKyc = false;
@Column(name = "virtual_debit_card")
private Boolean virtualDebitCard = false;
@Column(name = "created_date", nullable = false)
private LocalDateTime createdDate;
protected SavingsAccountFacilityConfig() {
this.createdDate = LocalDateTime.now();
}
public SavingsAccountFacilityConfig(SavingsAccount savingsAccount) {
this();
this.savingsAccount = savingsAccount;
}
public SavingsAccount getSavingsAccount() { return savingsAccount; }
public void setSavingsAccount(SavingsAccount savingsAccount) { this.savingsAccount = savingsAccount; }
public Boolean getAtmFacility() { return atmFacility; }
public void setAtmFacility(Boolean v) { this.atmFacility = v != null ? v : false; }
public Boolean getAtmWithdrawalFacility() { return atmWithdrawalFacility; }
public void setAtmWithdrawalFacility(Boolean v) { this.atmWithdrawalFacility = v != null ? v : false; }
public Boolean getUpiFacility() { return upiFacility; }
public void setUpiFacility(Boolean v) { this.upiFacility = v != null ? v : false; }
public Boolean getPosTransactionsFacility() { return posTransactionsFacility; }
public void setPosTransactionsFacility(Boolean v) { this.posTransactionsFacility = v != null ? v : false; }
public Boolean getChequeBook() { return chequeBook; }
public void setChequeBook(Boolean v) { this.chequeBook = v != null ? v : false; }
public Boolean getImpsFacility() { return impsFacility; }
public void setImpsFacility(Boolean v) { this.impsFacility = v != null ? v : false; }
public Boolean getSmsAlerts() { return smsAlerts; }
public void setSmsAlerts(Boolean v) { this.smsAlerts = v != null ? v : false; }
public Boolean getBbpsFacility() { return bbpsFacility; }
public void setBbpsFacility(Boolean v) { this.bbpsFacility = v != null ? v : false; }
public Boolean getInsuranceCover() { return insuranceCover; }
public void setInsuranceCover(Boolean v) { this.insuranceCover = v != null ? v : false; }
public Boolean getBepgFacility() { return bepgFacility; }
public void setBepgFacility(Boolean v) { this.bepgFacility = v != null ? v : false; }
public Boolean getNeftFacility() { return neftFacility; }
public void setNeftFacility(Boolean v) { this.neftFacility = v != null ? v : false; }
public Boolean getRtgsFacility() { return rtgsFacility; }
public void setRtgsFacility(Boolean v) { this.rtgsFacility = v != null ? v : false; }
public Boolean getInterBankTotalCapFacility() { return interBankTotalCapFacility; }
public void setInterBankTotalCapFacility(Boolean v) { this.interBankTotalCapFacility = v != null ? v : false; }
public Boolean getWithdrawalFacility() { return withdrawalFacility; }
public void setWithdrawalFacility(Boolean v) { this.withdrawalFacility = v != null ? v : false; }
public Boolean getDepositFacilityKyc() { return depositFacilityKyc; }
public void setDepositFacilityKyc(Boolean v) { this.depositFacilityKyc = v != null ? v : false; }
public Boolean getVirtualDebitCard() { return virtualDebitCard; }
public void setVirtualDebitCard(Boolean v) { this.virtualDebitCard = v != null ? v : false; }
public void updateFrom(com.google.gson.JsonObject config) {
if (config == null) return;
if (config.has("atmFacility")) setAtmFacility(config.get("atmFacility").getAsBoolean());
if (config.has("atmWithdrawalFacility")) setAtmWithdrawalFacility(config.get("atmWithdrawalFacility").getAsBoolean());
if (config.has("upiFacility")) setUpiFacility(config.get("upiFacility").getAsBoolean());
if (config.has("posTransactionsFacility")) setPosTransactionsFacility(config.get("posTransactionsFacility").getAsBoolean());
if (config.has("chequeBook")) setChequeBook(config.get("chequeBook").getAsBoolean());
if (config.has("impsFacility")) setImpsFacility(config.get("impsFacility").getAsBoolean());
if (config.has("smsAlerts")) setSmsAlerts(config.get("smsAlerts").getAsBoolean());
if (config.has("bbpsFacility")) setBbpsFacility(config.get("bbpsFacility").getAsBoolean());
if (config.has("insuranceCover")) setInsuranceCover(config.get("insuranceCover").getAsBoolean());
if (config.has("bepgFacility")) setBepgFacility(config.get("bepgFacility").getAsBoolean());
if (config.has("neftFacility")) setNeftFacility(config.get("neftFacility").getAsBoolean());
if (config.has("rtgsFacility")) setRtgsFacility(config.get("rtgsFacility").getAsBoolean());
if (config.has("interBankTotalCapFacility")) setInterBankTotalCapFacility(config.get("interBankTotalCapFacility").getAsBoolean());
if (config.has("withdrawalFacility")) setWithdrawalFacility(config.get("withdrawalFacility").getAsBoolean());
if (config.has("depositFacilityKyc")) setDepositFacilityKyc(config.get("depositFacilityKyc").getAsBoolean());
if (config.has("virtualDebitCard")) setVirtualDebitCard(config.get("virtualDebitCard").getAsBoolean());
}
}
@@ -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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.savings.domain;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface SavingsAccountFacilityConfigRepository extends JpaRepository<SavingsAccountFacilityConfig, Long> {
@Query("SELECT fc FROM SavingsAccountFacilityConfig fc WHERE fc.savingsAccount.id = :accountId")
Optional<SavingsAccountFacilityConfig> findBySavingsAccountId(@Param("accountId") Long accountId);
}
@@ -0,0 +1,81 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.savings.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity
@Table(name = "m_savings_account_joint_holders")
public class SavingsAccountJointHolder extends AbstractPersistableCustom<Long> {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "savings_account_id", nullable = false)
private SavingsAccount savingsAccount;
@Column(name = "client_id")
private Long clientId;
@Column(name = "cif_number", length = 50)
private String cifNumber;
@Column(name = "display_name", length = 200)
private String displayName;
@Column(name = "share_percentage", precision = 5, scale = 2)
private BigDecimal sharePercentage;
@Column(name = "signing_authority", length = 100)
private String signingAuthority;
@Column(name = "role", length = 100)
private String role;
@Column(name = "is_primary")
private boolean primary = false;
protected SavingsAccountJointHolder() {}
public SavingsAccountJointHolder(SavingsAccount account, Long clientId, String cifNumber,
String displayName, BigDecimal sharePercentage, String signingAuthority, String role, boolean primary) {
this.savingsAccount = account;
this.clientId = clientId;
this.cifNumber = cifNumber;
this.displayName = displayName;
this.sharePercentage = sharePercentage;
this.signingAuthority = signingAuthority;
this.role = role;
this.primary = primary;
}
public SavingsAccount getSavingsAccount() { return savingsAccount; }
public Long getClientId() { return clientId; }
public String getCifNumber() { return cifNumber; }
public String getDisplayName() { return displayName; }
public BigDecimal getSharePercentage() { return sharePercentage; }
public String getSigningAuthority() { return signingAuthority; }
public String getRole() { return role; }
public boolean isPrimary() { return primary; }
}
@@ -32,4 +32,5 @@
<include file="parts/2007_add_interest_calculation_type_option.xml" relativeToChangelogFile="true" />
<include file="parts/2008_add_other_gl_mappings_to_savings_product.xml" relativeToChangelogFile="true" />
<include file="parts/2009_add_gl_account_id_to_savings_product.xml" relativeToChangelogFile="true" />
<include file="parts/2010_add_savings_account_cbs_fields.xml" relativeToChangelogFile="true" />
</databaseChangeLog>
@@ -0,0 +1,174 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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. This file is licensed under the Apache License, Version 2.0.
-->
<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.3.xsd">
<!-- CBS extended fields on m_savings_account -->
<changeSet author="fineract" id="2010-add-savings-account-cbs-fields">
<addColumn tableName="m_savings_account">
<column name="cbs_account_type" type="VARCHAR(100)">
<constraints nullable="true"/>
</column>
<column name="customer_segment" type="VARCHAR(100)">
<constraints nullable="true"/>
</column>
<column name="account_status" type="VARCHAR(50)">
<constraints nullable="true"/>
</column>
<column name="mode_of_operation" type="VARCHAR(50)">
<constraints nullable="true"/>
</column>
<column name="special_category" type="VARCHAR(100)">
<constraints nullable="true"/>
</column>
<column name="weaker_section" type="VARCHAR(100)">
<constraints nullable="true"/>
</column>
<column name="guardian_name" type="VARCHAR(200)">
<constraints nullable="true"/>
</column>
<column name="guardian_cif_number" type="VARCHAR(50)">
<constraints nullable="true"/>
</column>
<column name="guardian_relationship" type="VARCHAR(100)">
<constraints nullable="true"/>
</column>
<column name="minor_date_of_birth" type="DATE">
<constraints nullable="true"/>
</column>
<column name="guardian_client_id" type="BIGINT">
<constraints nullable="true"/>
</column>
<column name="introducer_client_id" type="BIGINT">
<constraints nullable="true"/>
</column>
<column name="introducer_name" type="VARCHAR(200)">
<constraints nullable="true"/>
</column>
<column name="introducer_cif_number" type="VARCHAR(50)">
<constraints nullable="true"/>
</column>
<column name="nominee_data" type="TEXT">
<constraints nullable="true"/>
</column>
<column name="linked_account_id" type="BIGINT">
<constraints nullable="true"/>
</column>
<column name="linked_account_type" type="VARCHAR(20)">
<constraints nullable="true"/>
</column>
<column name="linked_account_no" type="VARCHAR(50)">
<constraints nullable="true"/>
</column>
</addColumn>
</changeSet>
<!-- Facility config table for savings accounts -->
<changeSet author="fineract" id="2010-create-savings-account-facility-config">
<createTable tableName="m_savings_account_facility_config">
<column name="id" type="BIGINT" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="savings_account_id" type="BIGINT">
<constraints nullable="false" unique="true"
foreignKeyName="fk_sa_facility_config_account"
references="m_savings_account(id)"/>
</column>
<column name="atm_facility" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="atm_withdrawal_facility" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="upi_facility" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="pos_transactions_facility" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="cheque_book" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="imps_facility" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="sms_alerts" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="bbps_facility" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="insurance_cover" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="bepg_facility" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="neft_facility" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="rtgs_facility" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="inter_bank_total_cap_facility" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="withdrawal_facility" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="deposit_facility_kyc" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="virtual_debit_card" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
<column name="created_date" type="DATETIME">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
<!-- Joint holders table for savings accounts -->
<changeSet author="fineract" id="2010-create-savings-account-joint-holders">
<createTable tableName="m_savings_account_joint_holders">
<column name="id" type="BIGINT" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="savings_account_id" type="BIGINT">
<constraints nullable="false"
foreignKeyName="fk_sa_joint_holder_account"
references="m_savings_account(id)"/>
</column>
<column name="client_id" type="BIGINT">
<constraints nullable="true"/>
</column>
<column name="cif_number" type="VARCHAR(50)">
<constraints nullable="true"/>
</column>
<column name="display_name" type="VARCHAR(200)">
<constraints nullable="true"/>
</column>
<column name="share_percentage" type="DECIMAL(5,2)">
<constraints nullable="true"/>
</column>
<column name="signing_authority" type="VARCHAR(100)">
<constraints nullable="true"/>
</column>
<column name="role" type="VARCHAR(100)">
<constraints nullable="true"/>
</column>
<column name="is_primary" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>
</databaseChangeLog>
@@ -112,6 +112,8 @@
<class>org.apache.fineract.portfolio.savings.domain.SavingsProductDepositLimitKyc</class>
<class>org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityConfig</class>
<class>org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityLimit</class>
<class>org.apache.fineract.portfolio.savings.domain.SavingsAccountFacilityConfig</class>
<class>org.apache.fineract.portfolio.savings.domain.SavingsAccountJointHolder</class>
<!-- Charge Module Entities -->
<class>org.apache.fineract.portfolio.charge.domain.Charge</class>