add gl mapping in the saving product,current product,rd product and also add genrate account no all three

This commit is contained in:
Nitesh Yadav
2026-04-26 02:02:56 +05:30
parent efb0511725
commit 159633f59a
31 changed files with 34724 additions and 34388 deletions
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
@@ -24,6 +24,7 @@ import java.util.Map;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.accounting.glaccount.domain.GLAccountRepository;
import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormat;
import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormatEnumerations.AccountNumberPrefixType;
import org.apache.fineract.infrastructure.codes.domain.CodeValue;
@@ -37,6 +38,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepository;
import org.apache.fineract.portfolio.savings.domain.SavingsProductRepository;
import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccount;
import org.springframework.stereotype.Component;
@@ -58,10 +60,15 @@ public class AccountNumberGenerator {
private static final String SAVINGS_PRODUCT_SHORT_NAME = "savingsProductShortName";
private static final String SHARE_PRODUCT_SHORT_NAME = "sharesProductShortName";
private static final String PREFIX_SHORT_NAME = "prefixShortName";
private static final int CBS_ACCOUNT_NUMBER_LENGTH = 15;
private static final String CBS_FIXED_PREFIX = "00";
private final ConfigurationReadPlatformService configurationReadPlatformService;
private final ClientRepository clientRepository;
private final LoanRepository loanRepository;
private final SavingsAccountRepository savingsAccountRepository;
private final GLAccountRepository glAccountRepository;
private final SavingsProductRepository savingsProductRepository;
public String generate(Client client, AccountNumberFormat accountNumberFormat) {
Map<String, String> propertyMap = new HashMap<>();
@@ -85,12 +92,64 @@ public class AccountNumberGenerator {
}
public String generate(SavingsAccount savingsAccount, AccountNumberFormat accountNumberFormat) {
Map<String, String> propertyMap = new HashMap<>();
propertyMap.put(ID, savingsAccount.getId().toString());
propertyMap.put(OFFICE_NAME, savingsAccount.office().getName());
propertyMap.put(SAVINGS_PRODUCT_SHORT_NAME, savingsAccount.savingsProduct().getShortName());
propertyMap.put(ENTITY_TYPE, "savingsAccount");
return generateAccountNumber(propertyMap, accountNumberFormat);
return generateCbsAccountNumber(savingsAccount);
}
private String generateCbsAccountNumber(SavingsAccount savingsAccount) {
// Format: [00][GL_CODE 6 digits][OFFICE_ID 2 digits][ACCOUNT_ID 5 digits] = 15 digits
Long glAccountId = savingsAccount.savingsProduct().getGlAccountId();
String glCode = "000000";
if (glAccountId != null) {
glCode = glAccountRepository.findById(glAccountId)
.map(gl -> StringUtils.leftPad(gl.getGlCode(), 6, '0'))
.orElse("000000");
}
glCode = glCode.length() > 6 ? glCode.substring(glCode.length() - 6) : StringUtils.leftPad(glCode, 6, '0');
String officeId = StringUtils.leftPad(savingsAccount.office().getId().toString(), 2, '0');
if (officeId.length() > 2) {
officeId = officeId.substring(officeId.length() - 2);
}
String accountId = StringUtils.leftPad(savingsAccount.getId().toString(), 5, '0');
if (accountId.length() > 5) {
accountId = accountId.substring(accountId.length() - 5);
}
return CBS_FIXED_PREFIX + glCode + officeId + accountId;
}
public String previewAccountNumber(Long productId, Long officeId) {
String glCode = "000000";
if (productId != null) {
glCode = savingsProductRepository.findById(productId).map(p -> {
Long glAccId = p.getGlAccountId();
if (glAccId == null) return "000000";
return glAccountRepository.findById(glAccId).map(gl -> gl.getGlCode()).orElse("000000");
}).orElse("000000");
}
return buildPreview(glCode, officeId);
}
public String previewAccountNumberByGlAccountId(Long glAccountId, Long officeId) {
String glCode = "000000";
if (glAccountId != null) {
glCode = glAccountRepository.findById(glAccountId).map(gl -> gl.getGlCode()).orElse("000000");
}
return buildPreview(glCode, officeId);
}
private String buildPreview(String glCode, Long officeId) {
glCode = glCode.length() > 6 ? glCode.substring(glCode.length() - 6) : StringUtils.leftPad(glCode, 6, '0');
String officeIdStr = officeId != null ? StringUtils.leftPad(officeId.toString(), 2, '0') : "00";
if (officeIdStr.length() > 2) officeIdStr = officeIdStr.substring(officeIdStr.length() - 2);
Long maxId = savingsAccountRepository.findMaxId().orElse(0L);
String nextSeq = StringUtils.leftPad(String.valueOf(maxId + 1), 5, '0');
if (nextSeq.length() > 5) nextSeq = nextSeq.substring(nextSeq.length() - 5);
return CBS_FIXED_PREFIX + glCode + officeIdStr + nextSeq;
}
public String generate(ShareAccount shareaccount, AccountNumberFormat accountNumberFormat) {
@@ -25,7 +25,9 @@ import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.portfolio.account.service.AccountNumberGenerator;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
@@ -63,6 +65,7 @@ import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.util.CollectionUtils;
@Slf4j
public class CurrentAccountTemplateReadPlatformServiceImpl implements CurrentAccountTemplateReadPlatformService {
private final PlatformSecurityContext context;
@@ -74,6 +77,7 @@ public class CurrentAccountTemplateReadPlatformServiceImpl implements CurrentAcc
private final SavingsDropdownReadPlatformService dropdownReadPlatformService;
private final ChargeReadPlatformService chargeReadPlatformService;
private final EntityDatatableChecksReadService entityDatatableChecksReadService;
private final AccountNumberGenerator accountNumberGenerator;
public CurrentAccountTemplateReadPlatformServiceImpl(final PlatformSecurityContext context, final JdbcTemplate jdbcTemplate,
final ClientReadPlatformService clientReadPlatformService, final GroupReadPlatformService groupReadPlatformService,
@@ -82,7 +86,8 @@ public class CurrentAccountTemplateReadPlatformServiceImpl implements CurrentAcc
final SavingsDropdownReadPlatformService dropdownReadPlatformService,
final ChargeReadPlatformService chargeReadPlatformService,
final EntityDatatableChecksReadService entityDatatableChecksReadService,
final ColumnValidator columnValidator) {
final ColumnValidator columnValidator,
final AccountNumberGenerator accountNumberGenerator) {
this.context = context;
this.jdbcTemplate = jdbcTemplate;
this.clientReadPlatformService = clientReadPlatformService;
@@ -92,6 +97,7 @@ public class CurrentAccountTemplateReadPlatformServiceImpl implements CurrentAcc
this.dropdownReadPlatformService = dropdownReadPlatformService;
this.chargeReadPlatformService = chargeReadPlatformService;
this.entityDatatableChecksReadService = entityDatatableChecksReadService;
this.accountNumberGenerator = accountNumberGenerator;
}
@Override
@@ -211,6 +217,13 @@ public class CurrentAccountTemplateReadPlatformServiceImpl implements CurrentAcc
template.setValidForPeriod(productData.getValidForPeriod());
template.setOdAccountClosedZeroBalanceInDayClosing(
productData.getOdAccountClosedZeroBalanceInDayClosing() != null && productData.getOdAccountClosedZeroBalanceInDayClosing());
// Generate preview account number using current product's own GL account ID
try {
final String preview = accountNumberGenerator.previewAccountNumberByGlAccountId(productData.getGlAccountId(), officeId);
template.setPreviewAccountNo(preview);
} catch (final Exception ex) {
log.warn("Failed to generate preview account number for productId={}: {}", productId, ex.getMessage());
}
}
} else {
@@ -46,6 +46,7 @@ import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.organisation.staff.data.StaffData;
import org.apache.fineract.organisation.staff.service.StaffReadPlatformService;
import org.apache.fineract.portfolio.account.PortfolioAccountType;
import org.apache.fineract.portfolio.account.service.AccountNumberGenerator;
import org.apache.fineract.portfolio.account.data.AccountTransferDTO;
import org.apache.fineract.portfolio.account.data.AccountTransferData;
import org.apache.fineract.portfolio.account.domain.AccountTransferType;
@@ -96,8 +97,10 @@ import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
@Slf4j
@RequiredArgsConstructor
public class DepositAccountReadPlatformServiceImpl implements DepositAccountReadPlatformService {
@@ -128,6 +131,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
private final DropdownReadPlatformService dropdownReadPlatformService;
private final CalendarReadPlatformService calendarReadPlatformService;
private final PaymentTypeReadService paymentTypeReadPlatformService;
private final AccountNumberGenerator accountNumberGenerator;
@Override
public Collection<DepositAccountData> retrieveAll(final DepositAccountType depositAccountType,
@@ -408,6 +412,13 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
// Re-apply CBS product fields lost during factory method object creation
((RecurringDepositAccountData) template).copyCbsFieldsFrom(rdTemplateWithCbs);
// Generate preview account number
try {
final String preview = accountNumberGenerator.previewAccountNumber(productId, officeId);
template.setPreviewAccountNo(preview);
} catch (final Exception ex) {
log.warn("Failed to generate preview account number for RD productId={}: {}", productId, ex.getMessage());
}
}
} else {
@@ -300,7 +300,7 @@ 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("sp.account_type as accountType, sp.customer_segment as customerSegment, ");
sqlBuilder.append("sp.product_code as productCode, ");
sqlBuilder.append("sp.product_code as productCode, 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, ");
@@ -327,6 +327,7 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead
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_code_value icv on icv.id = sp.interest_calculate_selector ");
sqlBuilder.append("left join acc_gl_account gla on gla.id = sp.gl_account_id ");
this.schemaSql = sqlBuilder.toString();
}
@@ -407,6 +408,8 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead
result.setAccountType(accountType);
result.setCustomerSegment(customerSegment);
result.setProductCode(productCode);
result.setGlAccountId(JdbcSupport.getLong(rs, "glAccountId"));
result.setGlAccountName(rs.getString("glAccountName"));
result.setEffectiveDate(effectiveDate);
result.setEffectiveTo(effectiveTo);
result.setEndDate(endDate);
@@ -47,6 +47,7 @@ import org.apache.fineract.portfolio.client.service.ClientReadPlatformService;
import org.apache.fineract.portfolio.group.data.GroupGeneralData;
import org.apache.fineract.portfolio.group.service.GroupReadPlatformService;
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
import org.apache.fineract.portfolio.account.service.AccountNumberGenerator;
import org.apache.fineract.portfolio.savings.SavingsCompoundingInterestPeriodType;
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationDaysInYearType;
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationType;
@@ -80,6 +81,7 @@ public class SavingsAccountTemplateReadPlatformServiceImpl implements SavingsAcc
private final CodeValueReadPlatformService codeValueReadPlatformService;
private final EntityDatatableChecksReadService entityDatatableChecksReadService;
private final AccountNumberGenerator accountNumberGenerator;
public SavingsAccountTemplateReadPlatformServiceImpl(final PlatformSecurityContext context, final JdbcTemplate jdbcTemplate,
final ClientReadPlatformService clientReadPlatformService, final GroupReadPlatformService groupReadPlatformService,
@@ -87,7 +89,8 @@ public class SavingsAccountTemplateReadPlatformServiceImpl implements SavingsAcc
final StaffReadPlatformService staffReadPlatformService, final SavingsDropdownReadPlatformService dropdownReadPlatformService,
final ChargeReadPlatformService chargeReadPlatformService,
final EntityDatatableChecksReadService entityDatatableChecksReadService, final ColumnValidator columnValidator,
final CodeValueReadPlatformService codeValueReadPlatformService) {
final CodeValueReadPlatformService codeValueReadPlatformService,
final AccountNumberGenerator accountNumberGenerator) {
this.context = context;
this.jdbcTemplate = jdbcTemplate;
this.clientReadPlatformService = clientReadPlatformService;
@@ -98,6 +101,7 @@ public class SavingsAccountTemplateReadPlatformServiceImpl implements SavingsAcc
this.chargeReadPlatformService = chargeReadPlatformService;
this.entityDatatableChecksReadService = entityDatatableChecksReadService;
this.codeValueReadPlatformService = codeValueReadPlatformService;
this.accountNumberGenerator = accountNumberGenerator;
}
@Override
@@ -237,6 +241,13 @@ public class SavingsAccountTemplateReadPlatformServiceImpl implements SavingsAcc
cv.getName()))
.toList();
template.setPeriodFrequencyOptions(periodFrequencyOptions);
// Generate preview account number based on product's GL account and office
try {
final String preview = accountNumberGenerator.previewAccountNumber(productId, officeId);
template.setPreviewAccountNo(preview);
} catch (final Exception ex) {
log.warn("Failed to generate preview account number for productId={}: {}", productId, ex.getMessage());
}
} catch (final Exception e) {
log.warn("Failed to enrich savings account template with CBS product data for productId={}: {}", productId, e.getMessage());
}
@@ -209,7 +209,7 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
sqlBuilder.append("sp.other_gl_mappings as otherGlMappings, ");
// Enhanced Field Selections
sqlBuilder.append("sp.account_type as accountType, sp.customer_segment as customerSegment, sp.product_code as productCode, ");
sqlBuilder.append("sp.account_type as accountType, sp.customer_segment as customerSegment, sp.product_code as productCode, 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, ");
@@ -223,6 +223,7 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
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_code_value icv on icv.id = sp.interest_calculate_selector ");
sqlBuilder.append("left join acc_gl_account gla on gla.id = sp.gl_account_id ");
this.schemaSql = sqlBuilder.toString();
}
@@ -321,6 +322,8 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
productData.setAccountType(rs.getString("accountType"));
productData.setCustomerSegment(rs.getString("customerSegment"));
productData.setProductCode(rs.getString("productCode"));
productData.setGlAccountId(JdbcSupport.getLong(rs, "glAccountId"));
productData.setGlAccountName(rs.getString("glAccountName"));
productData.setEffectiveDate(JdbcSupport.getLocalDate(rs, "effectiveDate"));
productData.setEffectiveTo(JdbcSupport.getLocalDate(rs, "effectiveTo"));
productData.setEndDate(JdbcSupport.getLocalDate(rs, "endDate"));
@@ -227,12 +227,13 @@ public class SavingsConfiguration {
SavingsDropdownReadPlatformService savingsDropdownReadPlatformService, ChargeReadPlatformService chargeReadPlatformService,
StaffReadPlatformService staffReadPlatformService, DepositsDropdownReadPlatformService depositsDropdownReadPlatformService,
SavingsAccountReadPlatformService savingsAccountReadPlatformService, DropdownReadPlatformService dropdownReadPlatformService,
CalendarReadPlatformService calendarReadPlatformService, PaymentTypeReadService paymentTypeReadPlatformService) {
CalendarReadPlatformService calendarReadPlatformService, PaymentTypeReadService paymentTypeReadPlatformService,
AccountNumberGenerator accountNumberGenerator) {
return new DepositAccountReadPlatformServiceImpl(context, jdbcTemplate, chartReadPlatformService, productChartReadPlatformService,
paginationParametersDataValidator, sqlGenerator, paginationHelper, clientReadPlatformService, groupReadPlatformService,
depositProductReadPlatformService, savingsDropdownReadPlatformService, chargeReadPlatformService, staffReadPlatformService,
depositsDropdownReadPlatformService, savingsAccountReadPlatformService, dropdownReadPlatformService,
calendarReadPlatformService, paymentTypeReadPlatformService);
calendarReadPlatformService, paymentTypeReadPlatformService, accountNumberGenerator);
}
@Bean
@@ -370,10 +371,11 @@ public class SavingsConfiguration {
GroupReadPlatformService groupReadPlatformService, SavingsProductReadPlatformService savingProductReadPlatformService,
StaffReadPlatformService staffReadPlatformService, SavingsDropdownReadPlatformService dropdownReadPlatformService,
ChargeReadPlatformService chargeReadPlatformService, EntityDatatableChecksReadService entityDatatableChecksReadService,
ColumnValidator columnValidator, CodeValueReadPlatformService codeValueReadPlatformService) {
ColumnValidator columnValidator, CodeValueReadPlatformService codeValueReadPlatformService,
AccountNumberGenerator accountNumberGenerator) {
return new SavingsAccountTemplateReadPlatformServiceImpl(context, jdbcTemplate, clientReadPlatformService, groupReadPlatformService,
savingProductReadPlatformService, staffReadPlatformService, dropdownReadPlatformService, chargeReadPlatformService,
entityDatatableChecksReadService, columnValidator, codeValueReadPlatformService);
entityDatatableChecksReadService, columnValidator, codeValueReadPlatformService, accountNumberGenerator);
}
@Bean
@@ -383,10 +385,10 @@ public class SavingsConfiguration {
GroupReadPlatformService groupReadPlatformService, CurrentProductReadPlatformService currentProductReadPlatformService,
StaffReadPlatformService staffReadPlatformService, SavingsDropdownReadPlatformService dropdownReadPlatformService,
ChargeReadPlatformService chargeReadPlatformService, EntityDatatableChecksReadService entityDatatableChecksReadService,
ColumnValidator columnValidator) {
ColumnValidator columnValidator, AccountNumberGenerator accountNumberGenerator) {
return new CurrentAccountTemplateReadPlatformServiceImpl(context, jdbcTemplate, clientReadPlatformService, groupReadPlatformService,
currentProductReadPlatformService, staffReadPlatformService, dropdownReadPlatformService, chargeReadPlatformService,
entityDatatableChecksReadService, columnValidator);
entityDatatableChecksReadService, columnValidator, accountNumberGenerator);
}
@Bean
@@ -276,4 +276,5 @@
<include file="parts/0270_add_rd_product_extra_fields.xml" relativeToChangelogFile="true"/>
<include file="parts/0271_create_rd_base_interest_rate_tables.xml" relativeToChangelogFile="true"/>
<include file="parts/0272_seed_rd_base_interest_rate_data.xml" relativeToChangelogFile="true"/>
<include file="parts/0273_add_gl_account_id_to_current_product.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
@@ -0,0 +1,34 @@
<?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. 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.
-->
<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 author="fineract" id="0273-add-gl-account-id-to-current-product">
<addColumn tableName="m_current_product">
<column name="gl_account_id" type="BIGINT">
<constraints nullable="true"
foreignKeyName="fk_current_product_gl_account"
references="acc_gl_account(id)"/>
</column>
</addColumn>
</changeSet>
</databaseChangeLog>