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
@@ -36,8 +36,13 @@ public interface ProductToGLAccountMappingRepository
@Param("chargeId") Long ChargeId);
@Query("select mapping from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.financialAccountType=:financialAccountType and mapping.paymentType is NULL and mapping.charge is NULL and mapping.chargeOffReason is NULL and mapping.writeOffReason is NULL and mapping.capitalizedIncomeClassification is NULL and mapping.buydownFeeClassification is NULL")
ProductToGLAccountMapping findCoreProductToFinAccountMapping(@Param("productId") Long productId, @Param("productType") int productType,
@Param("financialAccountType") int financialAccountType);
List<ProductToGLAccountMapping> findCoreProductToFinAccountMappings(@Param("productId") Long productId,
@Param("productType") int productType, @Param("financialAccountType") int financialAccountType);
default ProductToGLAccountMapping findCoreProductToFinAccountMapping(Long productId, int productType, int financialAccountType) {
List<ProductToGLAccountMapping> results = findCoreProductToFinAccountMappings(productId, productType, financialAccountType);
return results.isEmpty() ? null : results.get(0);
}
/***
* The financial Account Type for a fund source will always be an asset (1)
@@ -296,6 +296,7 @@ public final class DepositsApiConstants {
recurringDepositRequestData.add("accountType");
recurringDepositRequestData.add("customerSegment");
recurringDepositRequestData.add("productCode");
recurringDepositRequestData.add(SavingsApiConstants.glAccountIdParamName);
recurringDepositRequestData.add("effectiveTo");
recurringDepositRequestData.add("endDate");
recurringDepositRequestData.add("introducerRequired");
@@ -353,6 +354,8 @@ public final class DepositsApiConstants {
recurringDepositRequestData.add("accountType");
recurringDepositRequestData.add("customerSegment");
recurringDepositRequestData.add("productCode");
recurringDepositRequestData.add(SavingsApiConstants.glAccountIdParamName);
recurringDepositRequestData.add("glAccountName");
recurringDepositRequestData.add("effectiveDate");
recurringDepositRequestData.add("effectiveTo");
recurringDepositRequestData.add("endDate");
@@ -457,6 +460,8 @@ public final class DepositsApiConstants {
recurringDepositResponseData.add("accountType");
recurringDepositResponseData.add("customerSegment");
recurringDepositResponseData.add("productCode");
recurringDepositResponseData.add(SavingsApiConstants.glAccountIdParamName);
recurringDepositResponseData.add("glAccountName");
recurringDepositResponseData.add("effectiveDate");
recurringDepositResponseData.add("effectiveTo");
recurringDepositResponseData.add("endDate");
@@ -218,6 +218,7 @@ public class SavingsApiConstants {
public static final String accountTypeParamName = "accountType";
public static final String customerSegmentParamName = "customerSegment";
public static final String productCodeParamName = "productCode";
public static final String glAccountIdParamName = "glAccountId";
public static final String effectiveDateParamName = "effectiveDate";
public static final String effectiveToParamName = "effectiveTo";
public static final String endDateParamName = "endDate";
@@ -56,6 +56,7 @@ public final class SavingsAccountData implements Serializable {
private final Long id;
private final String accountNo;
private String previewAccountNo;
private final EnumOptionData depositType;
private final String externalId;
private final Long groupId;
@@ -126,6 +126,8 @@ public final class SavingsProductData implements Serializable {
@Getter @Setter private String accountType;
@Getter @Setter private String customerSegment;
@Getter @Setter private String productCode;
@Getter @Setter private Long glAccountId;
@Getter @Setter private String glAccountName;
@Getter @Setter private java.time.LocalDate effectiveDate;
@Getter @Setter private java.time.LocalDate effectiveTo;
@Getter @Setter private java.time.LocalDate endDate;
@@ -353,6 +355,8 @@ public final class SavingsProductData implements Serializable {
target.setAccountType(source.getAccountType());
target.setCustomerSegment(source.getCustomerSegment());
target.setProductCode(source.getProductCode());
target.setGlAccountId(source.getGlAccountId());
target.setGlAccountName(source.getGlAccountName());
target.setEffectiveDate(source.getEffectiveDate());
target.setEffectiveTo(source.getEffectiveTo());
target.setEndDate(source.getEndDate());
@@ -137,7 +137,8 @@ public class CurrentProductDataValidator {
SavingsApiConstants.balanceFrequencyParamName, SavingsApiConstants.accountClosedZeroBalanceInDayClosingParamName,
SavingsApiConstants.balanceSwapOptionParamName, SavingsApiConstants.msmeParamName,
SavingsApiConstants.autoDebitFacilityParamName, SavingsApiConstants.avgBalanceCalcPeriodParamName,
SavingsApiConstants.validForPeriodParamName, SavingsApiConstants.odAccountClosedZeroBalanceInDayClosingParamName));
SavingsApiConstants.validForPeriodParamName, SavingsApiConstants.odAccountClosedZeroBalanceInDayClosingParamName,
SavingsApiConstants.glAccountIdParamName));
public void validateForCreate(final String json) {
if (StringUtils.isBlank(json)) {
@@ -55,6 +55,7 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdraw
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.accountTypeParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.customerSegmentParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.productCodeParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.glAccountIdParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.effectiveDateParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.effectiveToParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.endDateParamName;
@@ -228,6 +229,9 @@ public class CurrentProduct extends AbstractPersistableCustom<Long> {
@Column(name = "product_code", length = 20, unique = true)
private String productCode;
@Column(name = "gl_account_id")
private Long glAccountId;
@Column(name = "effective_date")
private LocalDate effectiveDate;
@@ -734,6 +738,11 @@ public class CurrentProduct extends AbstractPersistableCustom<Long> {
actualChanges.put(productCodeParamName, newValue);
this.productCode = newValue;
}
if (command.isChangeInLongParameterNamed(glAccountIdParamName, this.glAccountId)) {
final Long newValue = command.longValueOfParameterNamed(glAccountIdParamName);
actualChanges.put(glAccountIdParamName, newValue);
this.glAccountId = newValue;
}
if (command.isChangeInBooleanParameterNamed(introducerRequiredParamName, this.introducerRequired)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(introducerRequiredParamName);
actualChanges.put(introducerRequiredParamName, newValue);
@@ -821,6 +830,8 @@ public class CurrentProduct extends AbstractPersistableCustom<Long> {
public void setCustomerSegment(String customerSegment) { this.customerSegment = customerSegment; }
public String getProductCode() { return productCode; }
public void setProductCode(String productCode) { this.productCode = productCode; }
public Long getGlAccountId() { return glAccountId; }
public void setGlAccountId(Long glAccountId) { this.glAccountId = glAccountId; }
public LocalDate getEffectiveDate() { return effectiveDate; }
public void setEffectiveDate(LocalDate effectiveDate) { this.effectiveDate = effectiveDate; }
public LocalDate getEffectiveTo() { return effectiveTo; }
@@ -71,6 +71,7 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominalA
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.otherGlMappingsParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.overdraftLimitParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.productCodeParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.glAccountIdParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.shareLinkingEnabledParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.shortNameParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.taxGroupIdParamName;
@@ -241,6 +242,9 @@ public class CurrentProductAssembler {
if (command.parameterExists(productCodeParamName)) {
product.setProductCode(command.stringValueOfParameterNamed(productCodeParamName));
}
if (command.parameterExists(glAccountIdParamName)) {
product.setGlAccountId(command.longValueOfParameterNamed(glAccountIdParamName));
}
if (command.parameterExists(effectiveDateParamName)) {
product.setEffectiveDate(command.localDateValueOfParameterNamed(effectiveDateParamName));
}
@@ -186,7 +186,7 @@ public class CurrentProductReadPlatformServiceImpl implements CurrentProductRead
sqlBuilder.append("cp.other_gl_mappings as otherGlMappings, ");
// Enhanced fields
sqlBuilder.append("cp.account_type as accountType, cp.customer_segment as customerSegment, cp.product_code as productCode, ");
sqlBuilder.append("cp.account_type as accountType, cp.customer_segment as customerSegment, cp.product_code as productCode, cp.gl_account_id as glAccountId, gla.name as glAccountName, ");
sqlBuilder.append("cp.effective_date as effectiveDate, cp.effective_to as effectiveTo, cp.end_date as endDate, ");
sqlBuilder.append("cp.introducer_required as introducerRequired, cp.share_linking_enabled as shareLinkingEnabled, ");
sqlBuilder.append("cp.nomination_facility as nominationFacility, cp.dormancy_alert as dormancyAlert, ");
@@ -202,6 +202,7 @@ public class CurrentProductReadPlatformServiceImpl implements CurrentProductRead
sqlBuilder.append("from m_current_product cp ");
sqlBuilder.append("join m_currency curr on curr.code = cp.currency_code ");
sqlBuilder.append("left join m_tax_group tg on tg.id = cp.tax_group_id ");
sqlBuilder.append("left join acc_gl_account gla on gla.id = cp.gl_account_id ");
this.schemaSql = sqlBuilder.toString();
}
@@ -297,6 +298,8 @@ public class CurrentProductReadPlatformServiceImpl implements CurrentProductRead
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"));
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>
@@ -44,7 +44,7 @@ public class SavingsApiSetConstants extends SavingsApiConstants {
daysToDormancyParamName, daysToInactiveParamName, accountMappingForPaymentParamName, "otherGlMappings", "otherGlMappingsMap", "accountTypeOptions",
"customerSegmentOptions", "yesNoOptions",
// Enhanced custom fields
"accountType", "customerSegment", "productCode", "effectiveDate", "effectiveTo", "endDate",
"accountType", "customerSegment", "productCode", "glAccountId", "glAccountName", "effectiveDate", "effectiveTo", "endDate",
"introducerRequired", "shareLinkingEnabled", "nominationFacility", "dormancyAlert",
"interestCalculateSelector", "averagePeriod", "autoPost", "frequencyFixDay", "lastInterestDate",
"enableLockinPeriod", "balanceFrequency", "accountClosedZeroBalanceInDayClosing",
@@ -82,7 +82,7 @@ public class SavingsApiSetConstants extends SavingsApiConstants {
"minBalanceForInterestCalculation", "minOverdraftForInterestCalculation",
"periodFrequencyOptions",
// CBS Product fields
"accountType", "customerSegment", "productCode", "effectiveTo", "endDate", "introducerRequired", "shareLinkingEnabled",
"accountType", "customerSegment", "productCode", "glAccountId", "glAccountName", "effectiveTo", "endDate", "introducerRequired", "shareLinkingEnabled",
"nominationFacility", "dormancyAlert", "enableLockinPeriod", "balanceFrequency",
"accountClosedZeroBalanceInDayClosing", "accountFacilityConfig", "accountFacilityLimits", "depositLimitKyc",
"interestCalculateSelector", "averagePeriod", "autoPost", "frequencyFixDay", "lastInterestDate",
@@ -38,6 +38,8 @@ public class DepositAccountData {
protected final Long id;
protected final String accountNo;
@lombok.Setter
protected String previewAccountNo;
protected final String externalId;
protected final Long groupId;
protected final String groupName;
@@ -65,6 +65,8 @@ public final class RecurringDepositProductData extends DepositProductData {
private String accountType;
private String customerSegment;
private String productCode;
private Long glAccountId;
private String glAccountName;
private java.time.LocalDate effectiveDate;
private java.time.LocalDate effectiveTo;
private java.time.LocalDate endDate;
@@ -105,6 +107,8 @@ 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 setGlAccountId(Long v) { this.glAccountId = v; }
public void setGlAccountName(String v) { this.glAccountName = 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; }
@@ -143,6 +147,8 @@ public final class RecurringDepositProductData extends DepositProductData {
this.accountType = src.accountType;
this.customerSegment = src.customerSegment;
this.productCode = src.productCode;
this.glAccountId = src.glAccountId;
this.glAccountName = src.glAccountName;
this.effectiveDate = src.effectiveDate;
this.effectiveTo = src.effectiveTo;
this.endDate = src.endDate;
@@ -186,6 +192,14 @@ public final class RecurringDepositProductData extends DepositProductData {
return productCode;
}
public Long getGlAccountId() {
return glAccountId;
}
public String getGlAccountName() {
return glAccountName;
}
public static RecurringDepositProductData template(final CurrencyData currency, final EnumOptionData interestCompoundingPeriodType,
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
final EnumOptionData interestCalculationDaysInYearType, final EnumOptionData accountingRule,
@@ -124,7 +124,8 @@ public class SavingsProductDataValidator {
SavingsApiConstants.accountFacilityConfigParamName, SavingsApiConstants.accountFacilityLimitsParamName,
SavingsApiConstants.depositLimitKycParamName,
// Additional custom fields
SavingsApiConstants.balanceFrequencyParamName, SavingsApiConstants.accountClosedZeroBalanceInDayClosingParamName));
SavingsApiConstants.balanceFrequencyParamName, SavingsApiConstants.accountClosedZeroBalanceInDayClosingParamName,
SavingsApiConstants.glAccountIdParamName));
public void validateForCreate(final String json) {
@@ -285,6 +285,9 @@ public class DepositProductAssembler {
recurringDepositProduct.setAccountType(command.stringValueOfParameterNamed("accountType"));
recurringDepositProduct.setCustomerSegment(command.stringValueOfParameterNamed("customerSegment"));
recurringDepositProduct.setProductCode(command.stringValueOfParameterNamed("productCode"));
if (command.parameterExists("glAccountId")) {
recurringDepositProduct.setGlAccountId(command.longValueOfParameterNamed("glAccountId"));
}
recurringDepositProduct.setEffectiveDate(parseCbsDate(command.stringValueOfParameterNamed("effectiveDate")));
recurringDepositProduct.setEffectiveTo(parseCbsDate(command.stringValueOfParameterNamed("effectiveTo")));
recurringDepositProduct.setEndDate(parseCbsDate(command.stringValueOfParameterNamed("endDate")));
@@ -22,6 +22,7 @@ import jakarta.persistence.LockModeType;
import java.time.LocalDate;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import org.apache.fineract.cob.data.COBIdAndLastClosedBusinessDate;
import org.apache.fineract.infrastructure.core.domain.ExternalId;
import org.apache.fineract.portfolio.savings.data.SavingsAccrualData;
@@ -147,4 +148,7 @@ public interface SavingsAccountRepository extends JpaRepository<SavingsAccount,
ORDER BY sa.lastClosedBusinessDate ASC
""")
List<COBIdAndLastClosedBusinessDate> findAllSavingsIdsOldestCobProcessed();
@Query("SELECT MAX(sa.id) FROM SavingsAccount sa")
Optional<Long> findMaxId();
}
@@ -56,6 +56,7 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdraw
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.accountTypeParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.customerSegmentParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.productCodeParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.glAccountIdParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.effectiveDateParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.effectiveToParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.endDateParamName;
@@ -248,6 +249,9 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
@Column(name = "product_code", length = 20, unique = true)
private String productCode;
@Column(name = "gl_account_id")
private Long glAccountId;
@Column(name = "effective_date")
private LocalDate effectiveDate;
@@ -796,6 +800,11 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
actualChanges.put(productCodeParamName, newValue);
this.productCode = newValue;
}
if (command.isChangeInLongParameterNamed(glAccountIdParamName, this.glAccountId)) {
final Long newValue = command.longValueOfParameterNamed(glAccountIdParamName);
actualChanges.put(glAccountIdParamName, newValue);
this.glAccountId = newValue;
}
if (command.parameterExists(effectiveDateParamName)) {
final LocalDate newValue = parseCbsLocalDate(command.stringValueOfParameterNamed(effectiveDateParamName));
if (!Objects.equals(newValue, this.effectiveDate)) {
@@ -1134,6 +1143,14 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
this.productCode = productCode;
}
public Long getGlAccountId() {
return glAccountId;
}
public void setGlAccountId(Long glAccountId) {
this.glAccountId = glAccountId;
}
public LocalDate getEffectiveDate() {
return effectiveDate;
}
@@ -36,6 +36,7 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.introduc
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.lastInterestDateParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominationFacilityParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.productCodeParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.glAccountIdParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.shareLinkingEnabledParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.chargesParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.currencyCodeParamName;
@@ -232,6 +233,9 @@ public class SavingsProductAssembler {
if (command.parameterExists(productCodeParamName)) {
product.setProductCode(command.stringValueOfParameterNamed(productCodeParamName));
}
if (command.parameterExists(glAccountIdParamName)) {
product.setGlAccountId(command.longValueOfParameterNamed(glAccountIdParamName));
}
if (command.parameterExists(effectiveDateParamName)) {
product.setEffectiveDate(command.localDateValueOfParameterNamed(effectiveDateParamName));
}
@@ -31,4 +31,5 @@
<include file="parts/2006_add_period_frequency_options.xml" relativeToChangelogFile="true" />
<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" />
</databaseChangeLog>
@@ -0,0 +1,22 @@
<?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">
<changeSet author="fineract" id="2009-add-gl-account-id-to-savings-product">
<addColumn tableName="m_savings_product">
<column name="gl_account_id" type="BIGINT">
<constraints nullable="true"
foreignKeyName="fk_savings_product_gl_account"
references="acc_gl_account(id)"/>
</column>
</addColumn>
</changeSet>
</databaseChangeLog>