add accountTypeOptions and customerSegmentOptions to savings/current/RD account templates

- Added accountTypeOptions and customerSegmentOptions fields to SavingsAccountData and RecurringDepositAccountData
- Added CodeValueReadPlatformService to SavingsAccountTemplateReadPlatformServiceImpl, CurrentAccountTemplateReadPlatformServiceImpl, and DepositAccountReadPlatformServiceImpl to fetch options from code values
- Added options to SAVINGS_ACCOUNT_RESPONSE_DATA_PARAMETERS and RD response parameters
- Updated SavingsConfiguration bean factory methods to pass new CodeValueReadPlatformService dependency
- Added validCheckSum for modified Liquibase changeset 0272
- Fixed AccountNumberGeneratorTest constructor to include GLAccountRepository and SavingsProductRepository

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Nitesh Yadav
2026-04-27 15:39:58 +05:30
co-authored by Claude Sonnet 4.6
parent 6ffcfff48e
commit 72adbf6305
10 changed files with 68 additions and 7 deletions
@@ -459,6 +459,8 @@ public final class DepositsApiConstants {
// CBS product fields — included in template response when productId is provided
recurringDepositResponseData.add("accountType");
recurringDepositResponseData.add("customerSegment");
recurringDepositResponseData.add("accountTypeOptions");
recurringDepositResponseData.add("customerSegmentOptions");
recurringDepositResponseData.add("productCode");
recurringDepositResponseData.add(SavingsApiConstants.glAccountIdParamName);
recurringDepositResponseData.add("glAccountName");
@@ -33,6 +33,7 @@ import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.jersey.serializer.legacy.JsonLocalDateArrayFormat;
import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
@@ -128,6 +129,8 @@ public final class SavingsAccountData implements Serializable {
// CBS Product fields (populated in template response from selected product)
private String accountType;
private String customerSegment;
private Collection<CodeValueData> accountTypeOptions;
private Collection<CodeValueData> customerSegmentOptions;
private String productCode;
private LocalDate effectiveDate;
private LocalDate effectiveTo;
@@ -26,7 +26,10 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
import org.apache.fineract.portfolio.account.service.AccountNumberGenerator;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
@@ -78,6 +81,7 @@ public class CurrentAccountTemplateReadPlatformServiceImpl implements CurrentAcc
private final ChargeReadPlatformService chargeReadPlatformService;
private final EntityDatatableChecksReadService entityDatatableChecksReadService;
private final AccountNumberGenerator accountNumberGenerator;
private final CodeValueReadPlatformService codeValueReadPlatformService;
public CurrentAccountTemplateReadPlatformServiceImpl(final PlatformSecurityContext context, final JdbcTemplate jdbcTemplate,
final ClientReadPlatformService clientReadPlatformService, final GroupReadPlatformService groupReadPlatformService,
@@ -87,7 +91,8 @@ public class CurrentAccountTemplateReadPlatformServiceImpl implements CurrentAcc
final ChargeReadPlatformService chargeReadPlatformService,
final EntityDatatableChecksReadService entityDatatableChecksReadService,
final ColumnValidator columnValidator,
final AccountNumberGenerator accountNumberGenerator) {
final AccountNumberGenerator accountNumberGenerator,
final CodeValueReadPlatformService codeValueReadPlatformService) {
this.context = context;
this.jdbcTemplate = jdbcTemplate;
this.clientReadPlatformService = clientReadPlatformService;
@@ -98,6 +103,7 @@ public class CurrentAccountTemplateReadPlatformServiceImpl implements CurrentAcc
this.chargeReadPlatformService = chargeReadPlatformService;
this.entityDatatableChecksReadService = entityDatatableChecksReadService;
this.accountNumberGenerator = accountNumberGenerator;
this.codeValueReadPlatformService = codeValueReadPlatformService;
}
@Override
@@ -204,6 +210,12 @@ public class CurrentAccountTemplateReadPlatformServiceImpl implements CurrentAcc
// Classification fields
template.setAccountType(productData.getAccountType());
template.setCustomerSegment(productData.getCustomerSegment());
final Collection<CodeValueData> accountTypeOpts = this.codeValueReadPlatformService
.retrieveCodeValuesByCode(SavingsApiConstants.CURRENT_PRODUCT_ACCOUNT_TYPE);
final Collection<CodeValueData> customerSegmentOpts = this.codeValueReadPlatformService
.retrieveCodeValuesByCode(SavingsApiConstants.CURRENT_PRODUCT_CUSTOMER_SEGMENT);
template.setAccountTypeOptions(accountTypeOpts);
template.setCustomerSegmentOptions(customerSegmentOpts);
template.setProductCode(productData.getProductCode());
template.setEffectiveDate(productData.getEffectiveDate());
template.setEffectiveTo(productData.getEffectiveTo());
@@ -32,6 +32,8 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.data.PaginationParameters;
import org.apache.fineract.infrastructure.core.data.PaginationParametersDataValidator;
@@ -70,6 +72,7 @@ import org.apache.fineract.portfolio.interestratechart.service.InterestRateChart
import org.apache.fineract.portfolio.paymentdetail.data.PaymentDetailData;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
import org.apache.fineract.portfolio.paymenttype.service.PaymentTypeReadService;
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
import org.apache.fineract.portfolio.savings.DepositAccountOnClosureType;
import org.apache.fineract.portfolio.savings.DepositAccountType;
import org.apache.fineract.portfolio.savings.SavingsAccountTransactionType;
@@ -132,6 +135,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
private final CalendarReadPlatformService calendarReadPlatformService;
private final PaymentTypeReadService paymentTypeReadPlatformService;
private final AccountNumberGenerator accountNumberGenerator;
private final CodeValueReadPlatformService codeValueReadPlatformService;
@Override
public Collection<DepositAccountData> retrieveAll(final DepositAccountType depositAccountType,
@@ -412,6 +416,18 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
// Re-apply CBS product fields lost during factory method object creation
((RecurringDepositAccountData) template).copyCbsFieldsFrom(rdTemplateWithCbs);
// Populate account type / customer segment options from code values
try {
final Collection<CodeValueData> accountTypeOpts = this.codeValueReadPlatformService
.retrieveCodeValuesByCode(SavingsApiConstants.RD_PRODUCT_ACCOUNT_TYPE);
final Collection<CodeValueData> customerSegmentOpts = this.codeValueReadPlatformService
.retrieveCodeValuesByCode(SavingsApiConstants.RD_PRODUCT_CUSTOMER_SEGMENT);
((RecurringDepositAccountData) template).setAccountTypeOptions(accountTypeOpts);
((RecurringDepositAccountData) template).setCustomerSegmentOptions(customerSegmentOpts);
} catch (final Exception ex) {
log.warn("Failed to load RD account type/customer segment options: {}", ex.getMessage());
}
// Generate preview account number
try {
final String preview = accountNumberGenerator.previewAccountNumber(productId, officeId);
@@ -27,6 +27,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Locale;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
@@ -194,6 +195,12 @@ public class SavingsAccountTemplateReadPlatformServiceImpl implements SavingsAcc
final SavingsProductData fullProduct = this.savingsProductReadPlatformService.retrieveOne(productId);
template.setAccountType(fullProduct.getAccountType());
template.setCustomerSegment(fullProduct.getCustomerSegment());
final Collection<CodeValueData> accountTypeOpts = this.codeValueReadPlatformService
.retrieveCodeValuesByCode(SavingsApiConstants.SAVINGS_PRODUCT_ACCOUNT_TYPE);
final Collection<CodeValueData> customerSegmentOpts = this.codeValueReadPlatformService
.retrieveCodeValuesByCode(SavingsApiConstants.SAVINGS_PRODUCT_CUSTOMER_SEGMENT);
template.setAccountTypeOptions(accountTypeOpts);
template.setCustomerSegmentOptions(customerSegmentOpts);
template.setProductCode(fullProduct.getProductCode());
template.setEffectiveDate(fullProduct.getEffectiveDate());
template.setEffectiveTo(fullProduct.getEffectiveTo());
@@ -228,12 +228,12 @@ public class SavingsConfiguration {
StaffReadPlatformService staffReadPlatformService, DepositsDropdownReadPlatformService depositsDropdownReadPlatformService,
SavingsAccountReadPlatformService savingsAccountReadPlatformService, DropdownReadPlatformService dropdownReadPlatformService,
CalendarReadPlatformService calendarReadPlatformService, PaymentTypeReadService paymentTypeReadPlatformService,
AccountNumberGenerator accountNumberGenerator) {
AccountNumberGenerator accountNumberGenerator, CodeValueReadPlatformService codeValueReadPlatformService) {
return new DepositAccountReadPlatformServiceImpl(context, jdbcTemplate, chartReadPlatformService, productChartReadPlatformService,
paginationParametersDataValidator, sqlGenerator, paginationHelper, clientReadPlatformService, groupReadPlatformService,
depositProductReadPlatformService, savingsDropdownReadPlatformService, chargeReadPlatformService, staffReadPlatformService,
depositsDropdownReadPlatformService, savingsAccountReadPlatformService, dropdownReadPlatformService,
calendarReadPlatformService, paymentTypeReadPlatformService, accountNumberGenerator);
calendarReadPlatformService, paymentTypeReadPlatformService, accountNumberGenerator, codeValueReadPlatformService);
}
@Bean
@@ -385,10 +385,11 @@ public class SavingsConfiguration {
GroupReadPlatformService groupReadPlatformService, CurrentProductReadPlatformService currentProductReadPlatformService,
StaffReadPlatformService staffReadPlatformService, SavingsDropdownReadPlatformService dropdownReadPlatformService,
ChargeReadPlatformService chargeReadPlatformService, EntityDatatableChecksReadService entityDatatableChecksReadService,
ColumnValidator columnValidator, AccountNumberGenerator accountNumberGenerator) {
ColumnValidator columnValidator, AccountNumberGenerator accountNumberGenerator,
CodeValueReadPlatformService codeValueReadPlatformService) {
return new CurrentAccountTemplateReadPlatformServiceImpl(context, jdbcTemplate, clientReadPlatformService, groupReadPlatformService,
currentProductReadPlatformService, staffReadPlatformService, dropdownReadPlatformService, chargeReadPlatformService,
entityDatatableChecksReadService, columnValidator, accountNumberGenerator);
entityDatatableChecksReadService, columnValidator, accountNumberGenerator, codeValueReadPlatformService);
}
@Bean
@@ -5,6 +5,7 @@
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<changeSet id="0272_insert_rd_base_rate_version" author="fineract">
<validCheckSum>9:4cb4d062d4ee9464fe5a4e32023580c2</validCheckSum>
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_rd_base_interest_rate_effective</sqlCheck>
</preConditions>
@@ -30,6 +30,7 @@ import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationC
import org.apache.fineract.infrastructure.configuration.data.GlobalConfigurationPropertyData;
import org.apache.fineract.infrastructure.configuration.service.ConfigurationReadPlatformService;
import org.apache.fineract.organisation.office.domain.Office;
import org.apache.fineract.accounting.glaccount.domain.GLAccountRepository;
import org.apache.fineract.portfolio.account.service.AccountNumberGenerator;
import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.client.domain.ClientRepository;
@@ -39,6 +40,7 @@ import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepository;
import org.apache.fineract.portfolio.savings.domain.SavingsProduct;
import org.apache.fineract.portfolio.savings.domain.SavingsProductRepository;
import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccount;
import org.apache.fineract.portfolio.shareproducts.domain.ShareProduct;
import org.junit.jupiter.api.BeforeEach;
@@ -50,6 +52,8 @@ public class AccountNumberGeneratorTest {
private ClientRepository clientRepo;
private LoanRepository loanRepo;
private SavingsAccountRepository savingsRepo;
private GLAccountRepository glAccountRepo;
private SavingsProductRepository savingsProductRepo;
private AccountNumberGenerator generator;
@@ -59,8 +63,10 @@ public class AccountNumberGeneratorTest {
clientRepo = mock(ClientRepository.class);
loanRepo = mock(LoanRepository.class);
savingsRepo = mock(SavingsAccountRepository.class);
glAccountRepo = mock(GLAccountRepository.class);
savingsProductRepo = mock(SavingsProductRepository.class);
generator = new AccountNumberGenerator(configService, clientRepo, loanRepo, savingsRepo);
generator = new AccountNumberGenerator(configService, clientRepo, loanRepo, savingsRepo, glAccountRepo, savingsProductRepo);
GlobalConfigurationPropertyData accountLengthConfig = mock(GlobalConfigurationPropertyData.class);
when(accountLengthConfig.getValue()).thenReturn(Long.valueOf("9"));
@@ -82,7 +82,7 @@ public class SavingsApiSetConstants extends SavingsApiConstants {
"minBalanceForInterestCalculation", "minOverdraftForInterestCalculation",
"periodFrequencyOptions",
// CBS Product fields
"accountType", "customerSegment", "productCode", "glAccountId", "glAccountName", "effectiveTo", "endDate", "introducerRequired", "shareLinkingEnabled",
"accountType", "customerSegment", "accountTypeOptions", "customerSegmentOptions", "productCode", "glAccountId", "glAccountName", "effectiveTo", "endDate", "introducerRequired", "shareLinkingEnabled",
"nominationFacility", "dormancyAlert", "enableLockinPeriod", "balanceFrequency",
"accountClosedZeroBalanceInDayClosing", "accountFacilityConfig", "accountFacilityLimits", "depositLimitKyc",
"interestCalculateSelector", "averagePeriod", "autoPost", "frequencyFixDay", "lastInterestDate",
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.savings.data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Collection;
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
import lombok.Getter;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
@@ -86,6 +87,8 @@ public final class RecurringDepositAccountData extends DepositAccountData {
// CBS product fields (populated from product template)
private String accountType;
private String customerSegment;
private Collection<CodeValueData> accountTypeOptions;
private Collection<CodeValueData> customerSegmentOptions;
private String productCode;
private LocalDate effectiveDate;
private LocalDate effectiveTo;
@@ -122,10 +125,20 @@ public final class RecurringDepositAccountData extends DepositAccountData {
private Boolean deceasedSettlement;
private Boolean allowDebitTxnAfterDueDate;
public void setAccountTypeOptions(Collection<CodeValueData> accountTypeOptions) {
this.accountTypeOptions = accountTypeOptions;
}
public void setCustomerSegmentOptions(Collection<CodeValueData> customerSegmentOptions) {
this.customerSegmentOptions = customerSegmentOptions;
}
public void copyCbsFieldsFrom(final RecurringDepositAccountData src) {
if (src == null) return;
this.accountType = src.accountType;
this.customerSegment = src.customerSegment;
this.accountTypeOptions = src.accountTypeOptions;
this.customerSegmentOptions = src.customerSegmentOptions;
this.productCode = src.productCode;
this.effectiveDate = src.effectiveDate;
this.effectiveTo = src.effectiveTo;