feat: multi-nominee support, duplicate validation, and FD/RD required fields

Account Creation Enhancements:
- Added multi-nominee support for SB, CA, FD, RD accounts (nominees[] array)
- Backend: saveNomineesIfPresent() validates total share <= 100% before saving
- Added 'nominees' to parameter whitelists (SavingsAccountConstant, DepositsApiConstants)

Duplicate Validation Fixes:
- SB/FD/RD: Fixed duplicate externalId error handler to walk full exception cause
  chain (EclipseLink wraps PSQLException deep) — now matches constraint
  'm_savings_account_external_id_key' and returns proper 400 error
- CA: Added try-catch around both saveAndFlush calls for duplicate externalId
  (constraint: ca_unq_external_id) with throwIfDuplicateExternalId() helper
- CA: Added duplicate product check — blocks creating same product twice for client
- SB/FD/RD: Added JpaSystemException handling via getAllCauseMessages() helper

Current Account (CA) Improvements:
- CurrentAccount entity: added @UniqueConstraint for external_id (ca_unq_external_id)
- CurrentAccountRepository: added countActiveByClientAndProduct() JPQL query
- Liquibase 0298: unique constraint on m_current_account.external_id

FD/RD Required Field Validation (Backend):
- DepositAccountDataValidator: depositPeriod now required for RD (was FD-only)
- DepositAccountDataValidator: mandatoryRecommendedDepositAmount now notNull+positive for RD
- DepositAccountDataValidator: customerSegment now required (notBlank) for both FD and RD

Liquibase Migrations:
- 0297: fix unique nominee per account constraint
- 0298: unique external_id on m_current_account
- 2014: add is_mandatory column to m_savings_account_joint_holders

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Nitesh Yadav
2026-05-20 08:00:00 +05:30
co-authored by Claude Sonnet 4.6
parent 9d67afec3e
commit cc0ccbb461
18 changed files with 291 additions and 28 deletions
@@ -53,6 +53,17 @@ public interface ClientNomineeRepository extends JpaRepository<ClientNominee, Lo
@Param("nomineeClientId") Long nomineeClientId,
@Param("accountType") String accountType);
@Query("SELECT COUNT(n) FROM ClientNominee n "
+ "WHERE n.client.id = :clientId "
+ "AND n.nomineeClient.id = :nomineeClientId "
+ "AND n.accountNo = :accountNo "
+ "AND n.accountType = :accountType "
+ "AND n.isDeleted = false")
long countActiveByClientNomineeAndAccountNoAndType(@Param("clientId") Long clientId,
@Param("nomineeClientId") Long nomineeClientId,
@Param("accountNo") String accountNo,
@Param("accountType") String accountType);
@Query("SELECT COUNT(n) FROM ClientNominee n "
+ "WHERE n.client.id = :clientId "
+ "AND n.nomineeClient.id = :nomineeClientId "
@@ -537,6 +537,7 @@ public final class DepositsApiConstants {
fixedDepositRequestData.add(SavingsApiConstants.introducerNameParamName);
fixedDepositRequestData.add(SavingsApiConstants.introducerCifNumberParamName);
fixedDepositRequestData.add(SavingsApiConstants.nomineeParamName);
fixedDepositRequestData.add("nominees");
fixedDepositRequestData.add(SavingsApiConstants.linkedAccountIdParamName);
fixedDepositRequestData.add(SavingsApiConstants.linkedAccountTypeParamName);
fixedDepositRequestData.add(SavingsApiConstants.linkedAccountNoParamName);
@@ -603,6 +604,7 @@ public final class DepositsApiConstants {
recurringDepositRequestData.add(SavingsApiConstants.introducerNameParamName);
recurringDepositRequestData.add(SavingsApiConstants.introducerCifNumberParamName);
recurringDepositRequestData.add(SavingsApiConstants.nomineeParamName);
recurringDepositRequestData.add("nominees");
recurringDepositRequestData.add(SavingsApiConstants.linkedAccountIdParamName);
recurringDepositRequestData.add(SavingsApiConstants.linkedAccountTypeParamName);
recurringDepositRequestData.add(SavingsApiConstants.linkedAccountNoParamName);