feat(fd): add Renewal Grace Period product field, both storage paths

New per-FD-product "Renewal Grace Period (Days)" term field: null/0 (every existing product)
keeps today's instant, same-night auto-renewal; a positive value is later read by the nightly
maturity job and the manual Renew action to decide whether/how a matured FD waits for staff to
act instead of renewing itself.

Wired into the live product path end-to-end -- DepositsApiConstants param, DepositTermDetail
column + diffing, DepositProductAssembler (create and update), DepositProductReadPlatformServiceImpl,
FixedDepositProductData -- migration 0572 adds the column.

Also wired into the maker-checker pending-edit mirror (m_saving_product_temp /
FixedDepositEditFields / ProductPendingEditFieldMapper), a second, independent storage path a
governed product edit uses -- without this the field silently dropped out of a checker's
"Proposed changes" review even though it was submitted. Migration 0573 adds its column.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-24 15:55:11 +05:30
co-authored by Claude Sonnet 5
parent a7cb09f15c
commit ecfe8aa76a
9 changed files with 117 additions and 8 deletions
@@ -309,6 +309,7 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead
sqlBuilder.append("dptp.in_multiples_of_deposit_term_type_enum as inMultiplesOfDepositTermTypeId, ");
sqlBuilder.append("dptp.min_deposit_amount as minDepositAmount, dptp.deposit_amount as depositAmount, ");
sqlBuilder.append("dptp.max_deposit_amount as maxDepositAmount, ");
sqlBuilder.append("dptp.renewal_grace_period_days as renewalGracePeriodDays, ");
sqlBuilder.append("sp.account_type as accountType, sp.fd_type as fdType, sp.product_code as productCode, ");
sqlBuilder.append("sp.customer_segment as customerSegment, ");
sqlBuilder.append("sp.gl_account_id as glAccountId, gla.name as glAccountName, ");
@@ -385,6 +386,7 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead
// CBS Custom Fields
result.setAccountType(rs.getString("accountType"));
result.setFdType(rs.getString("fdType"));
result.setRenewalGracePeriodDays(JdbcSupport.getInteger(rs, "renewalGracePeriodDays"));
result.setProductCode(rs.getString("productCode"));
result.setCustomerSegment(rs.getString("customerSegment"));
result.setGlAccountId(JdbcSupport.getLong(rs, "glAccountId"));
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<!--
Days after maturity a depositor can still walk in and have their FD renewed backdated to the
original maturity date, at the currently active rate. Null/0 (every existing product, since
this column is brand new) means "no grace period configured", so that product keeps the
instant, same-night auto-renewal it always had; see
DepositAccountWritePlatformServiceJpaRepositoryImpl#updateMaturityDetails, which only skips
the automatic renewal when this is a positive value. So adding this column changes nothing
for any product until an admin explicitly sets a grace period on it.
-->
<changeSet id="0572_add_renewal_grace_period_to_deposit_product_term" author="CBS">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="m_deposit_product_term_and_preclosure" columnName="renewal_grace_period_days"/></not>
</preConditions>
<addColumn tableName="m_deposit_product_term_and_preclosure">
<column name="renewal_grace_period_days" type="INTEGER"/>
</addColumn>
</changeSet>
</databaseChangeLog>
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<!--
m_saving_product_temp is a full field-by-field mirror of the product tables, used by the
maker-checker "pending product edit" flow (ProductPendingEditFieldMapper /
FixedDepositEditFields, an @Embeddable mapped directly onto this table). It is a separate
storage path from the live product tables migration 0572 added a column to, so
renewalGracePeriodDays needs its own column here too, or a governed FD/RD product edit that
sets it silently drops the value: the checker's "Proposed changes" screen never shows it,
and approving the edit never carries it forward, even though the value was actually typed in
and submitted.
-->
<changeSet id="0573_add_renewal_grace_period_to_saving_product_temp" author="CBS">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="m_saving_product_temp" columnName="renewal_grace_period_days"/></not>
</preConditions>
<addColumn tableName="m_saving_product_temp">
<column name="renewal_grace_period_days" type="INTEGER"/>
</addColumn>
</changeSet>
</databaseChangeLog>