feat(accounts): backend fixes for Modify Application feature (Current/Savings/FD/RD)
Current Account: - CurrentAccountReadPlatformServiceImpl: add retrieveJointHolders() and retrievePartners() - CurrentAccountWritePlatformServiceImpl: full modifyApplication() - updates all CBS fields, joint holders, partners, nominees, facility config, dates, introducer - Fix cbsAccountType save: parse string account type from 'accountType' JSON field Nominees: - ClientNomineeWritePlatformService: add replaceNomineesForAccount() for atomic replace - Savings/FD/RD modifyApplication: replace nominees on modify FD/RD Read (DepositAccountReadPlatformServiceImpl): - Add isSeniorCitizen, seniorCitizenInterestRate to BASE SQL SELECT - Add setCbsAccountFields() call in FD/RD mappers reading accountStatus, modeOfOperation, introducerClientId, guardianFields, linkedAccountId, isSeniorCitizen from ResultSet - Fix retrieveOne() to also fetch joint holders from m_savings_account_joint_holders - Use explicit LinkedHashMap in joint holder query (camelCase keys for Angular) FD/RD Data Classes: - FixedDepositAccountData: add accountStatus, modeOfOperation, introducerClientId, linkedAccountId, jointHolders, isSeniorCitizen, seniorCitizenInterestRate fields - RecurringDepositAccountData: same fields added - Fix all factory methods (withInterestChartAndRecurringDetails, withClosureTemplateDetails, withTemplateOptions, associationsAndTemplate) to call copyCbsFieldsFrom() - Fix SavingsAccountReadPlatformServiceImpl joint holders: use camelCase keys FD Calculator: - FixedDepositAccountInterestCalculationServiceImpl: add calculateExact() with actual calendar-based calculation matching PostingPeriod engine (exact same as account creation) - Add submittedOnDate, daysInYear, interestPostingPeriodInMonths optional params - Support interestCompoundingPeriodInMonths=0 (daily compounding) in both validator and calc - DepositsApiConstants: add submittedOnDate/dateFormat/locale/daysInYear to allowed params - DepositAccountDataValidator: allow 0 (daily) in interestCompoundingPeriodInMonths Misc: - SavingsProductData: null-check in isCashBased/isAccrualBased methods (NPE fix) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
7c4cf6260c
commit
a051faba5d
+5
@@ -512,6 +512,11 @@ public final class DepositsApiConstants {
|
|||||||
fixedDepositInterestCalculationData.add(tenureInMonthsParamName);
|
fixedDepositInterestCalculationData.add(tenureInMonthsParamName);
|
||||||
fixedDepositInterestCalculationData.add(interestPostingPeriodInMonthsParamName);
|
fixedDepositInterestCalculationData.add(interestPostingPeriodInMonthsParamName);
|
||||||
fixedDepositInterestCalculationData.add(interestCompoundingPeriodInMonthsParamName);
|
fixedDepositInterestCalculationData.add(interestCompoundingPeriodInMonthsParamName);
|
||||||
|
// Exact calendar-based calculation params
|
||||||
|
fixedDepositInterestCalculationData.add("submittedOnDate");
|
||||||
|
fixedDepositInterestCalculationData.add("dateFormat");
|
||||||
|
fixedDepositInterestCalculationData.add("locale");
|
||||||
|
fixedDepositInterestCalculationData.add("daysInYear");
|
||||||
|
|
||||||
return fixedDepositInterestCalculationData;
|
return fixedDepositInterestCalculationData;
|
||||||
|
|
||||||
|
|||||||
+3
@@ -692,6 +692,7 @@ public final class SavingsProductData implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCashBasedAccountingEnabled() {
|
public boolean isCashBasedAccountingEnabled() {
|
||||||
|
if (this.accountingRule == null) return false;
|
||||||
return AccountingRuleType.CASH_BASED.getValue().toString().equals(this.accountingRule.getValue());
|
return AccountingRuleType.CASH_BASED.getValue().toString().equals(this.accountingRule.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -700,10 +701,12 @@ public final class SavingsProductData implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isUpfrontAccrualAccounting() {
|
public boolean isUpfrontAccrualAccounting() {
|
||||||
|
if (this.accountingRule == null) return false;
|
||||||
return AccountingRuleType.ACCRUAL_UPFRONT.getValue().toString().equals(this.accountingRule.getValue());
|
return AccountingRuleType.ACCRUAL_UPFRONT.getValue().toString().equals(this.accountingRule.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPeriodicAccrualAccounting() {
|
public boolean isPeriodicAccrualAccounting() {
|
||||||
|
if (this.accountingRule == null) return false;
|
||||||
return AccountingRuleType.ACCRUAL_PERIODIC.getValue().toString().equals(this.accountingRule.getValue());
|
return AccountingRuleType.ACCRUAL_PERIODIC.getValue().toString().equals(this.accountingRule.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+37030
-34544
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+6
@@ -38,4 +38,10 @@ public interface ClientNomineeWritePlatformService {
|
|||||||
void saveNomineeIfPresent(Long clientId, String accountNo, String accountType, JsonElement nomineeJson);
|
void saveNomineeIfPresent(Long clientId, String accountNo, String accountType, JsonElement nomineeJson);
|
||||||
|
|
||||||
void saveNomineesIfPresent(Long clientId, String accountNo, String accountType, JsonElement nomineesJson);
|
void saveNomineesIfPresent(Long clientId, String accountNo, String accountType, JsonElement nomineesJson);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Soft-deletes all existing nominees for the given account, then saves the new nominees.
|
||||||
|
* Used during modifyApplication to replace nominees atomically.
|
||||||
|
*/
|
||||||
|
void replaceNomineesForAccount(Long clientId, String accountNo, String accountType, JsonElement nomineesJson);
|
||||||
}
|
}
|
||||||
|
|||||||
+16
@@ -465,4 +465,20 @@ public class ClientNomineeWritePlatformServiceImpl implements ClientNomineeWrite
|
|||||||
saveNomineeIfPresent(clientId, accountNo, accountType, nomineesJson);
|
saveNomineeIfPresent(clientId, accountNo, accountType, nomineesJson);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void replaceNomineesForAccount(final Long clientId, final String accountNo, final String accountType, final JsonElement nomineesJson) {
|
||||||
|
// Soft-delete all existing nominees for this account
|
||||||
|
final List<org.apache.fineract.portfolio.client.domain.ClientNominee> existing =
|
||||||
|
nomineeRepository.findByClientIdAndAccountNoAndAccountType(clientId, accountNo, accountType);
|
||||||
|
for (org.apache.fineract.portfolio.client.domain.ClientNominee n : existing) {
|
||||||
|
n.setIsDeleted(true);
|
||||||
|
n.setIsActive(false);
|
||||||
|
}
|
||||||
|
nomineeRepository.saveAll(existing);
|
||||||
|
// Save new nominees
|
||||||
|
if (nomineesJson != null && !nomineesJson.isJsonNull()) {
|
||||||
|
saveNomineesIfPresent(clientId, accountNo, accountType, nomineesJson);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-6
@@ -257,24 +257,34 @@ public class FixedDepositAccountsApiResource {
|
|||||||
@Produces({ MediaType.APPLICATION_JSON })
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = FixedDepositAccountsApiResourceSwagger.CalculateFixedDepositInterestResponse.class)))
|
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = FixedDepositAccountsApiResourceSwagger.CalculateFixedDepositInterestResponse.class)))
|
||||||
public String calculateFixedDepositInterest(@Context final UriInfo uriInfo,
|
public String calculateFixedDepositInterest(@Context final UriInfo uriInfo,
|
||||||
@QueryParam("principalAmount") @Parameter(description = "BigDecimal principalAmount") final BigDecimal principalAmount,
|
@QueryParam("principalAmount") @Parameter(description = "Deposit principal amount") final BigDecimal principalAmount,
|
||||||
@QueryParam("annualInterestRate") @Parameter(description = "annualInterestRate") final BigDecimal annualInterestRate,
|
@QueryParam("annualInterestRate") @Parameter(description = "Annual interest rate (%)") final BigDecimal annualInterestRate,
|
||||||
@QueryParam("tenureInMonths") @Parameter(description = "tenureInMonths") final Long tenureInMonths,
|
@QueryParam("tenureInMonths") @Parameter(description = "Tenure in months") final Long tenureInMonths,
|
||||||
@QueryParam("interestCompoundingPeriodInMonths") @Parameter(description = "interestCompoundingPeriodInMonths") final Long interestCompoundingPeriodInMonths,
|
@QueryParam("interestCompoundingPeriodInMonths") @Parameter(description = "Compounding period in months (1,3,6,12)") final Long interestCompoundingPeriodInMonths,
|
||||||
@QueryParam("interestPostingPeriodInMonths") @Parameter(description = "interestPostingPeriodInMonths") final Long interestPostingPeriodInMonths) {
|
@QueryParam("interestPostingPeriodInMonths") @Parameter(description = "Posting period in months (1,3,6,12)") final Long interestPostingPeriodInMonths,
|
||||||
|
@QueryParam("submittedOnDate") @Parameter(description = "Submission date (yyyy-MM-dd) for exact calendar calculation") final String submittedOnDate,
|
||||||
|
@QueryParam("daysInYear") @Parameter(description = "Days in year (360 or 365)") final Integer daysInYear) {
|
||||||
HashMap request = new HashMap<>();
|
HashMap request = new HashMap<>();
|
||||||
request.put("annualInterestRate", annualInterestRate);
|
request.put("annualInterestRate", annualInterestRate);
|
||||||
request.put("tenureInMonths", tenureInMonths);
|
request.put("tenureInMonths", tenureInMonths);
|
||||||
request.put("interestCompoundingPeriodInMonths", interestCompoundingPeriodInMonths);
|
request.put("interestCompoundingPeriodInMonths", interestCompoundingPeriodInMonths);
|
||||||
request.put("interestPostingPeriodInMonths", interestPostingPeriodInMonths);
|
request.put("interestPostingPeriodInMonths", interestPostingPeriodInMonths);
|
||||||
request.put("principalAmount", principalAmount);
|
request.put("principalAmount", principalAmount);
|
||||||
|
// Pass exact calculation params if provided
|
||||||
|
if (submittedOnDate != null && !submittedOnDate.isBlank()) {
|
||||||
|
request.put("submittedOnDate", submittedOnDate); // pass as string, extracted in service
|
||||||
|
request.put("dateFormat", "yyyy-MM-dd");
|
||||||
|
request.put("locale", "en");
|
||||||
|
}
|
||||||
|
if (daysInYear != null) {
|
||||||
|
request.put("daysInYear", daysInYear);
|
||||||
|
}
|
||||||
String apiRequestBodyAsJson = toApiJsonSerializer.serialize(request);
|
String apiRequestBodyAsJson = toApiJsonSerializer.serialize(request);
|
||||||
JsonElement jsonElement = fromJsonHelper.parse(apiRequestBodyAsJson);
|
JsonElement jsonElement = fromJsonHelper.parse(apiRequestBodyAsJson);
|
||||||
HashMap result = fixedDepositAccountInterestCalculationService
|
HashMap result = fixedDepositAccountInterestCalculationService
|
||||||
.calculateInterest(new JsonQuery(apiRequestBodyAsJson, jsonElement, fromJsonHelper));
|
.calculateInterest(new JsonQuery(apiRequestBodyAsJson, jsonElement, fromJsonHelper));
|
||||||
|
|
||||||
return toApiJsonSerializer.serializeResult(result);
|
return toApiJsonSerializer.serializeResult(result);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private BigDecimal getActivationCharge(Long accountId) {
|
private BigDecimal getActivationCharge(Long accountId) {
|
||||||
|
|||||||
+6
-4
@@ -628,13 +628,15 @@ public class DepositAccountDataValidator {
|
|||||||
element);
|
element);
|
||||||
baseDataValidator.reset().parameter(interestCompoundingPeriodInMonthsParamName).value(interestCompoundingPeriodInMonths).notNull();
|
baseDataValidator.reset().parameter(interestCompoundingPeriodInMonthsParamName).value(interestCompoundingPeriodInMonths).notNull();
|
||||||
|
|
||||||
List<Long> allowedValues = List.of(1L, 2L, 3L, 4L, 6L, 12L);
|
// 0 = daily compounding (handled by calculateExact); 1,2,3,4,6,12 = periodic
|
||||||
|
List<Long> allowedValues = List.of(0L, 1L, 2L, 3L, 4L, 6L, 12L);
|
||||||
if (interestCompoundingPeriodInMonths != null && !allowedValues.contains(interestCompoundingPeriodInMonths)) {
|
if (interestCompoundingPeriodInMonths != null && !allowedValues.contains(interestCompoundingPeriodInMonths)) {
|
||||||
baseDataValidator.reset().parameter(interestCompoundingPeriodInMonthsParamName).value(interestCompoundingPeriodInMonths)
|
baseDataValidator.reset().parameter(interestCompoundingPeriodInMonthsParamName).value(interestCompoundingPeriodInMonths)
|
||||||
.failWithCode("parameter.value.error", "interestCompoundingPeriodInMonths can only be one {1,2,3,4,6,12}");
|
.failWithCode("parameter.value.error", "interestCompoundingPeriodInMonths can only be one {0,1,2,3,4,6,12}");
|
||||||
}
|
}
|
||||||
if (interestCompoundingPeriodInMonths != null && tenureInMonths != null
|
// Divisibility check only for periodic (non-daily) compounding
|
||||||
&& tenureInMonths % interestCompoundingPeriodInMonths != 0) {
|
if (interestCompoundingPeriodInMonths != null && interestCompoundingPeriodInMonths > 0
|
||||||
|
&& tenureInMonths != null && tenureInMonths % interestCompoundingPeriodInMonths != 0) {
|
||||||
baseDataValidator.reset().parameter(interestCompoundingPeriodInMonthsParamName).value(interestCompoundingPeriodInMonths)
|
baseDataValidator.reset().parameter(interestCompoundingPeriodInMonthsParamName).value(interestCompoundingPeriodInMonths)
|
||||||
.failWithCode("parameter.relational.validation",
|
.failWithCode("parameter.relational.validation",
|
||||||
"tenureInMonths must be perfectly divisible by interestCompoundingPeriodInMonths");
|
"tenureInMonths must be perfectly divisible by interestCompoundingPeriodInMonths");
|
||||||
|
|||||||
+42
@@ -66,11 +66,53 @@ public class CurrentAccountReadPlatformServiceImpl implements CurrentAccountRead
|
|||||||
throw new CurrentAccountNotFoundException(accountId);
|
throw new CurrentAccountNotFoundException(accountId);
|
||||||
}
|
}
|
||||||
final Map<String, Object> response = buildStructuredResponse(rows.get(0));
|
final Map<String, Object> response = buildStructuredResponse(rows.get(0));
|
||||||
|
response.put("jointHolders", retrieveJointHolders(accountId));
|
||||||
|
response.put("partners", retrievePartners(accountId));
|
||||||
response.put("charges", retrieveCharges(accountId));
|
response.put("charges", retrieveCharges(accountId));
|
||||||
response.put("transactions", retrieveTransactions(accountId));
|
response.put("transactions", retrieveTransactions(accountId));
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Map<String, Object>> retrieveJointHolders(Long accountId) {
|
||||||
|
final String sql =
|
||||||
|
"SELECT jh.id, jh.client_id, jh.cif_number, jh.display_name, "
|
||||||
|
+ "jh.share_percentage, jh.signing_authority, jh.role, jh.is_primary, jh.is_mandatory "
|
||||||
|
+ "FROM m_current_account_joint_holder jh "
|
||||||
|
+ "WHERE jh.current_account_id = ? "
|
||||||
|
+ "ORDER BY jh.is_primary DESC, jh.id ASC";
|
||||||
|
return jdbcTemplate.query(sql, (rs, rowNum) -> {
|
||||||
|
final Map<String, Object> h = new LinkedHashMap<>();
|
||||||
|
h.put("id", rs.getLong("id"));
|
||||||
|
h.put("clientId", rs.getLong("client_id"));
|
||||||
|
h.put("cifNumber", rs.getString("cif_number"));
|
||||||
|
h.put("displayName", rs.getString("display_name"));
|
||||||
|
h.put("sharePercentage", rs.getBigDecimal("share_percentage"));
|
||||||
|
h.put("signingAuthority", rs.getString("signing_authority"));
|
||||||
|
h.put("role", rs.getString("role"));
|
||||||
|
h.put("isPrimary", rs.getBoolean("is_primary"));
|
||||||
|
h.put("isMandatory", rs.getBoolean("is_mandatory"));
|
||||||
|
return h;
|
||||||
|
}, accountId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Map<String, Object>> retrievePartners(Long accountId) {
|
||||||
|
final String sql =
|
||||||
|
"SELECT p.id, p.client_id, p.client_cif, p.client_name, p.share_percentage, p.is_mandatory "
|
||||||
|
+ "FROM m_current_account_partner p "
|
||||||
|
+ "WHERE p.current_account_id = ? "
|
||||||
|
+ "ORDER BY p.id ASC";
|
||||||
|
return jdbcTemplate.query(sql, (rs, rowNum) -> {
|
||||||
|
final Map<String, Object> p = new LinkedHashMap<>();
|
||||||
|
p.put("id", rs.getLong("id"));
|
||||||
|
p.put("clientId", rs.getLong("client_id"));
|
||||||
|
p.put("clientCif", rs.getString("client_cif"));
|
||||||
|
p.put("clientName", rs.getString("client_name"));
|
||||||
|
p.put("sharePercentage", rs.getBigDecimal("share_percentage"));
|
||||||
|
p.put("isMandatory", rs.getBoolean("is_mandatory"));
|
||||||
|
return p;
|
||||||
|
}, accountId);
|
||||||
|
}
|
||||||
|
|
||||||
private List<Map<String, Object>> retrieveTransactions(Long accountId) {
|
private List<Map<String, Object>> retrieveTransactions(Long accountId) {
|
||||||
final String sql =
|
final String sql =
|
||||||
"SELECT t.id, t.transaction_type_enum, t.transaction_date, t.amount, "
|
"SELECT t.id, t.transaction_type_enum, t.transaction_date, t.amount, "
|
||||||
|
|||||||
+83
-10
@@ -106,12 +106,18 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri
|
|||||||
LocalDate submittedOnDate = parseDate(getString(json, "submittedOnDate"), dateFormat, locale);
|
LocalDate submittedOnDate = parseDate(getString(json, "submittedOnDate"), dateFormat, locale);
|
||||||
if (submittedOnDate == null) submittedOnDate = LocalDate.now();
|
if (submittedOnDate == null) submittedOnDate = LocalDate.now();
|
||||||
|
|
||||||
// accountType may arrive as integer or descriptive string — store null if unparseable
|
// accountType (Fineract enum: 1=individual, 2=group) — try int, else default 1
|
||||||
Integer accountTypeEnum = null;
|
Integer accountTypeEnum = 1;
|
||||||
|
// cbsAccountType — descriptive string e.g. "Standard Account" sent as "accountType"
|
||||||
|
String cbsAccountType = null;
|
||||||
if (json.has("accountType") && !json.get("accountType").isJsonNull()) {
|
if (json.has("accountType") && !json.get("accountType").isJsonNull()) {
|
||||||
|
final String rawAccountType = json.get("accountType").getAsString();
|
||||||
try {
|
try {
|
||||||
accountTypeEnum = json.get("accountType").getAsInt();
|
accountTypeEnum = Integer.parseInt(rawAccountType);
|
||||||
} catch (Exception ignored) { }
|
} catch (Exception ignored) {
|
||||||
|
// It's a descriptive CBS account type string, not an enum int
|
||||||
|
cbsAccountType = rawAccountType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean msme = json.has("msme") && !json.get("msme").isJsonNull()
|
boolean msme = json.has("msme") && !json.get("msme").isJsonNull()
|
||||||
@@ -134,6 +140,9 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri
|
|||||||
product.getInterestCalculateSelector(), product.getAveragePeriod(),
|
product.getInterestCalculateSelector(), product.getAveragePeriod(),
|
||||||
product.getAvgBalanceCalcPeriod());
|
product.getAvgBalanceCalcPeriod());
|
||||||
|
|
||||||
|
// Save CBS account type (descriptive name: "Standard Account", "Basic Account", etc.)
|
||||||
|
if (cbsAccountType != null) account.setCbsAccountType(cbsAccountType);
|
||||||
|
|
||||||
// Copy product-level fields that are not in createNew()
|
// Copy product-level fields that are not in createNew()
|
||||||
account.setMinRequiredOpeningBalance(product.getMinRequiredOpeningBalance());
|
account.setMinRequiredOpeningBalance(product.getMinRequiredOpeningBalance());
|
||||||
account.setMinRequiredBalance(product.getMinRequiredBalance());
|
account.setMinRequiredBalance(product.getMinRequiredBalance());
|
||||||
@@ -389,16 +398,80 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri
|
|||||||
context.authenticatedUser();
|
context.authenticatedUser();
|
||||||
final CurrentAccount account = findAccount(accountId);
|
final CurrentAccount account = findAccount(accountId);
|
||||||
final JsonObject json = command.parsedJson().getAsJsonObject();
|
final JsonObject json = command.parsedJson().getAsJsonObject();
|
||||||
if (json.has("msme") && !json.get("msme").isJsonNull()) {
|
|
||||||
account.setMsme(json.get("msme").getAsBoolean());
|
if (json.has("externalId") && !json.get("externalId").isJsonNull())
|
||||||
|
account.setExternalId(json.get("externalId").getAsString());
|
||||||
|
if (json.has("accountStatus") && !json.get("accountStatus").isJsonNull())
|
||||||
|
account.setAccountStatus(json.get("accountStatus").getAsString());
|
||||||
|
if (json.has("accountType") && !json.get("accountType").isJsonNull()) {
|
||||||
|
final String rawAt = json.get("accountType").getAsString();
|
||||||
|
try { Integer.parseInt(rawAt); } catch (Exception ignored) {
|
||||||
|
// descriptive CBS type — save it
|
||||||
|
account.setCbsAccountType(rawAt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (json.has("signatoryRights") && !json.get("signatoryRights").isJsonNull()) {
|
if (json.has("customerSegment") && !json.get("customerSegment").isJsonNull())
|
||||||
account.setSignatoryRights(json.get("signatoryRights").getAsString());
|
account.setCustomerSegment(json.get("customerSegment").getAsString());
|
||||||
}
|
if (json.has("modeOfOperation") && !json.get("modeOfOperation").isJsonNull())
|
||||||
if (json.has("modeOfOperation") && !json.get("modeOfOperation").isJsonNull()) {
|
|
||||||
account.setModeOfOperation(json.get("modeOfOperation").getAsString());
|
account.setModeOfOperation(json.get("modeOfOperation").getAsString());
|
||||||
|
if (json.has("signatoryRights") && !json.get("signatoryRights").isJsonNull())
|
||||||
|
account.setSignatoryRights(json.get("signatoryRights").getAsString());
|
||||||
|
if (json.has("msme") && !json.get("msme").isJsonNull())
|
||||||
|
account.setMsme(json.get("msme").getAsBoolean());
|
||||||
|
if (json.has("balanceSwapOption") && !json.get("balanceSwapOption").isJsonNull())
|
||||||
|
account.setBalanceSwapOption(json.get("balanceSwapOption").getAsBoolean());
|
||||||
|
if (json.has("autoDebitFacility") && !json.get("autoDebitFacility").isJsonNull())
|
||||||
|
account.setAutoDebitFacility(json.get("autoDebitFacility").getAsBoolean());
|
||||||
|
if (json.has("introducerClientId") && !json.get("introducerClientId").isJsonNull())
|
||||||
|
account.setIntroducerClientId(json.get("introducerClientId").getAsLong());
|
||||||
|
if (json.has("introducerName") && !json.get("introducerName").isJsonNull())
|
||||||
|
account.setIntroducerName(json.get("introducerName").getAsString());
|
||||||
|
if (json.has("introducerCifNumber") && !json.get("introducerCifNumber").isJsonNull())
|
||||||
|
account.setIntroducerCifNumber(json.get("introducerCifNumber").getAsString());
|
||||||
|
|
||||||
|
// dates
|
||||||
|
final String dateFormat = json.has("dateFormat") && !json.get("dateFormat").isJsonNull()
|
||||||
|
? json.get("dateFormat").getAsString() : "dd MMMM yyyy";
|
||||||
|
if (json.has("establishmentDate") && !json.get("establishmentDate").isJsonNull()) {
|
||||||
|
try {
|
||||||
|
account.setEstablishmentDate(LocalDate.parse(json.get("establishmentDate").getAsString(),
|
||||||
|
DateTimeFormatter.ofPattern(dateFormat)));
|
||||||
|
} catch (Exception ignored) {}
|
||||||
}
|
}
|
||||||
|
if (json.has("startOperationDate") && !json.get("startOperationDate").isJsonNull()) {
|
||||||
|
try {
|
||||||
|
account.setStartOperationDate(LocalDate.parse(json.get("startOperationDate").getAsString(),
|
||||||
|
DateTimeFormatter.ofPattern(dateFormat)));
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// facility config
|
||||||
|
JsonObject fcJson = json.has("accountFacilityConfig") && !json.get("accountFacilityConfig").isJsonNull()
|
||||||
|
? json.getAsJsonObject("accountFacilityConfig") : null;
|
||||||
|
if (fcJson == null && json.has("facilityConfig") && !json.get("facilityConfig").isJsonNull())
|
||||||
|
fcJson = json.getAsJsonObject("facilityConfig");
|
||||||
|
if (fcJson != null) account.setFacilityConfig(assembleFacilityConfig(account, fcJson));
|
||||||
|
|
||||||
|
// joint holders — clear and re-add
|
||||||
|
if (json.has("jointHolders") && json.get("jointHolders").isJsonArray()) {
|
||||||
|
account.getJointHolders().clear();
|
||||||
|
assembleJointHolders(account, json.getAsJsonArray("jointHolders"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// partners — clear and re-add
|
||||||
|
if (json.has("partners") && json.get("partners").isJsonArray()) {
|
||||||
|
account.getPartners().clear();
|
||||||
|
assemblePartners(account, json.getAsJsonArray("partners"));
|
||||||
|
}
|
||||||
|
|
||||||
currentAccountRepository.saveAndFlush(account);
|
currentAccountRepository.saveAndFlush(account);
|
||||||
|
|
||||||
|
// nominees — replace existing with new (done after flush to ensure accountNo is stable)
|
||||||
|
if (json.has("nominees") && !json.get("nominees").isJsonNull()) {
|
||||||
|
clientNomineeWritePlatformService.replaceNomineesForAccount(
|
||||||
|
account.getClient().getId(), account.getAccountNo(), "CB", json.get("nominees"));
|
||||||
|
}
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder().withEntityId(accountId).build();
|
return new CommandProcessingResultBuilder().withEntityId(accountId).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+48
-1
@@ -309,13 +309,44 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
|
|||||||
sqlBuilder.append(depositAccountMapper.schema());
|
sqlBuilder.append(depositAccountMapper.schema());
|
||||||
sqlBuilder.append(" where sa.id = ? and sa.deposit_type_enum = ? ");
|
sqlBuilder.append(" where sa.id = ? and sa.deposit_type_enum = ? ");
|
||||||
|
|
||||||
return this.jdbcTemplate.queryForObject(sqlBuilder.toString(), depositAccountMapper, accountId, depositAccountType.getValue());
|
final DepositAccountData account = this.jdbcTemplate.queryForObject(sqlBuilder.toString(), depositAccountMapper, accountId, depositAccountType.getValue());
|
||||||
|
if (account != null) {
|
||||||
|
final java.util.List<java.util.Map<String, Object>> jointHolders = retrieveJointHolders(accountId);
|
||||||
|
if (!jointHolders.isEmpty()) {
|
||||||
|
if (account instanceof org.apache.fineract.portfolio.savings.data.FixedDepositAccountData) {
|
||||||
|
((org.apache.fineract.portfolio.savings.data.FixedDepositAccountData) account).setJointHolders(jointHolders);
|
||||||
|
} else if (account instanceof org.apache.fineract.portfolio.savings.data.RecurringDepositAccountData) {
|
||||||
|
((org.apache.fineract.portfolio.savings.data.RecurringDepositAccountData) account).setJointHolders(jointHolders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return account;
|
||||||
|
|
||||||
} catch (final EmptyResultDataAccessException e) {
|
} catch (final EmptyResultDataAccessException e) {
|
||||||
throw new DepositAccountNotFoundException(depositAccountType, accountId, e);
|
throw new DepositAccountNotFoundException(depositAccountType, accountId, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private java.util.List<java.util.Map<String, Object>> retrieveJointHolders(final Long accountId) {
|
||||||
|
final String sql = "SELECT jh.id, jh.client_id, jh.cif_number, jh.display_name, "
|
||||||
|
+ "jh.share_percentage, jh.signing_authority, jh.role, jh.is_primary, jh.is_mandatory "
|
||||||
|
+ "FROM m_savings_account_joint_holders jh WHERE jh.savings_account_id = ? "
|
||||||
|
+ "ORDER BY jh.is_primary DESC, jh.id ASC";
|
||||||
|
return this.jdbcTemplate.query(sql, (rs, rowNum) -> {
|
||||||
|
final java.util.Map<String, Object> h = new java.util.LinkedHashMap<>();
|
||||||
|
h.put("id", rs.getLong("id"));
|
||||||
|
h.put("clientId", rs.getLong("client_id"));
|
||||||
|
h.put("cifNumber", rs.getString("cif_number"));
|
||||||
|
h.put("displayName", rs.getString("display_name"));
|
||||||
|
h.put("sharePercentage", rs.getBigDecimal("share_percentage"));
|
||||||
|
h.put("signingAuthority", rs.getString("signing_authority"));
|
||||||
|
h.put("role", rs.getString("role"));
|
||||||
|
h.put("isPrimary", rs.getBoolean("is_primary"));
|
||||||
|
h.put("isMandatory", rs.getBoolean("is_mandatory"));
|
||||||
|
return h;
|
||||||
|
}, accountId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DepositAccountData retrieveOneWithClosureTemplate(final DepositAccountType depositAccountType, final Long accountId) {
|
public DepositAccountData retrieveOneWithClosureTemplate(final DepositAccountType depositAccountType, final Long accountId) {
|
||||||
try {
|
try {
|
||||||
@@ -812,6 +843,8 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
|
|||||||
selectFieldsSqlBuilder.append("sa.introducer_cif_number as introducerCifNumber, ");
|
selectFieldsSqlBuilder.append("sa.introducer_cif_number as introducerCifNumber, ");
|
||||||
selectFieldsSqlBuilder.append("sa.linked_account_id as linkedAccountId, sa.linked_account_type as linkedAccountType, ");
|
selectFieldsSqlBuilder.append("sa.linked_account_id as linkedAccountId, sa.linked_account_type as linkedAccountType, ");
|
||||||
selectFieldsSqlBuilder.append("sa.linked_account_no as linkedAccountNo, ");
|
selectFieldsSqlBuilder.append("sa.linked_account_no as linkedAccountNo, ");
|
||||||
|
selectFieldsSqlBuilder.append("COALESCE(sa.is_senior_citizen, false) as isSeniorCitizen, ");
|
||||||
|
selectFieldsSqlBuilder.append("sa.senior_citizen_interest_rate as seniorCitizenInterestRate, ");
|
||||||
selectFieldsSqlBuilder.append("sa.min_balance_for_interest_calculation as minBalanceForInterestCalculation, ");
|
selectFieldsSqlBuilder.append("sa.min_balance_for_interest_calculation as minBalanceForInterestCalculation, ");
|
||||||
selectFieldsSqlBuilder.append("sa.withhold_tax as withHoldTax,");
|
selectFieldsSqlBuilder.append("sa.withhold_tax as withHoldTax,");
|
||||||
selectFieldsSqlBuilder.append("tg.id as taxGroupId, tg.name as taxGroupName ");
|
selectFieldsSqlBuilder.append("tg.id as taxGroupId, tg.name as taxGroupName ");
|
||||||
@@ -1111,6 +1144,13 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
|
|||||||
rs.getBoolean("creditMaturityProceeds"), rs.getBoolean("penaltyGracePeriodMissedInstallments"),
|
rs.getBoolean("creditMaturityProceeds"), rs.getBoolean("penaltyGracePeriodMissedInstallments"),
|
||||||
rs.getBoolean("panelRequestApplicable"), rs.getBoolean("noPenaltyNomineeHeirClosure"),
|
rs.getBoolean("panelRequestApplicable"), rs.getBoolean("noPenaltyNomineeHeirClosure"),
|
||||||
rs.getBoolean("deceasedSettlement"), rs.getBoolean("allowDebitTxnAfterDueDate"));
|
rs.getBoolean("deceasedSettlement"), rs.getBoolean("allowDebitTxnAfterDueDate"));
|
||||||
|
result.setCbsAccountFields(rs.getString("accountStatus"), rs.getString("modeOfOperation"),
|
||||||
|
JdbcSupport.getLong(rs, "introducerClientId"), rs.getString("introducerName"),
|
||||||
|
rs.getString("introducerCifNumber"), rs.getString("specialCategory"), rs.getString("weakerSection"),
|
||||||
|
rs.getString("guardianName"), rs.getString("guardianCifNumber"), rs.getString("guardianRelationship"),
|
||||||
|
JdbcSupport.getLong(rs, "guardianClientId"), JdbcSupport.getLocalDate(rs, "minorDateOfBirth"),
|
||||||
|
JdbcSupport.getLong(rs, "linkedAccountId"),
|
||||||
|
rs.getBoolean("isSeniorCitizen"), JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "seniorCitizenInterestRate"));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1268,6 +1308,13 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
|
|||||||
rs.getBoolean("creditMaturityProceeds"), rs.getBoolean("penaltyGracePeriodMissedInstallments"),
|
rs.getBoolean("creditMaturityProceeds"), rs.getBoolean("penaltyGracePeriodMissedInstallments"),
|
||||||
rs.getBoolean("panelRequestApplicable"), rs.getBoolean("noPenaltyNomineeHeirClosure"),
|
rs.getBoolean("panelRequestApplicable"), rs.getBoolean("noPenaltyNomineeHeirClosure"),
|
||||||
rs.getBoolean("deceasedSettlement"), rs.getBoolean("allowDebitTxnAfterDueDate"));
|
rs.getBoolean("deceasedSettlement"), rs.getBoolean("allowDebitTxnAfterDueDate"));
|
||||||
|
result.setCbsAccountFields(rs.getString("accountStatus"), rs.getString("modeOfOperation"),
|
||||||
|
JdbcSupport.getLong(rs, "introducerClientId"), rs.getString("introducerName"),
|
||||||
|
rs.getString("introducerCifNumber"), rs.getString("specialCategory"), rs.getString("weakerSection"),
|
||||||
|
rs.getString("guardianName"), rs.getString("guardianCifNumber"), rs.getString("guardianRelationship"),
|
||||||
|
JdbcSupport.getLong(rs, "guardianClientId"), JdbcSupport.getLocalDate(rs, "minorDateOfBirth"),
|
||||||
|
JdbcSupport.getLong(rs, "linkedAccountId"),
|
||||||
|
rs.getBoolean("isSeniorCitizen"), JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "seniorCitizenInterestRate"));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
|||||||
+20
@@ -467,6 +467,16 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Replace nominees if provided
|
||||||
|
final com.google.gson.JsonElement parsedJsonFd = command.parsedJson();
|
||||||
|
if (parsedJsonFd != null && parsedJsonFd.isJsonObject()) {
|
||||||
|
final com.google.gson.JsonObject jsonObjFd = parsedJsonFd.getAsJsonObject();
|
||||||
|
if (jsonObjFd.has("nominees") && !jsonObjFd.get("nominees").isJsonNull()) {
|
||||||
|
clientNomineeWritePlatformService.replaceNomineesForAccount(
|
||||||
|
account.clientId(), account.getAccountNumber(), "FD", jsonObjFd.get("nominees"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withCommandId(command.commandId()) //
|
.withCommandId(command.commandId()) //
|
||||||
.withEntityId(accountId) //
|
.withEntityId(accountId) //
|
||||||
@@ -539,6 +549,16 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
|||||||
this.calendarInstanceRepository.save(calendarInstance);
|
this.calendarInstanceRepository.save(calendarInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Replace nominees if provided
|
||||||
|
final com.google.gson.JsonElement parsedJsonRd = command.parsedJson();
|
||||||
|
if (parsedJsonRd != null && parsedJsonRd.isJsonObject()) {
|
||||||
|
final com.google.gson.JsonObject jsonObjRd = parsedJsonRd.getAsJsonObject();
|
||||||
|
if (jsonObjRd.has("nominees") && !jsonObjRd.get("nominees").isJsonNull()) {
|
||||||
|
clientNomineeWritePlatformService.replaceNomineesForAccount(
|
||||||
|
account.clientId(), account.getAccountNumber(), "RD", jsonObjRd.get("nominees"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withCommandId(command.commandId()) //
|
.withCommandId(command.commandId()) //
|
||||||
.withEntityId(accountId) //
|
.withEntityId(accountId) //
|
||||||
|
|||||||
+79
-6
@@ -27,6 +27,9 @@ import static org.apache.fineract.portfolio.savings.DepositsApiConstants.tenureI
|
|||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.fineract.infrastructure.core.api.JsonQuery;
|
import org.apache.fineract.infrastructure.core.api.JsonQuery;
|
||||||
@@ -49,21 +52,91 @@ public class FixedDepositAccountInterestCalculationServiceImpl implements FixedD
|
|||||||
BigDecimal principalAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(principalAmountParamName, element);
|
BigDecimal principalAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(principalAmountParamName, element);
|
||||||
BigDecimal annualInterestRate = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(annualInterestRateParamName, element);
|
BigDecimal annualInterestRate = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(annualInterestRateParamName, element);
|
||||||
Long tenureInMonths = this.fromApiJsonHelper.extractLongNamed(tenureInMonthsParamName, element);
|
Long tenureInMonths = this.fromApiJsonHelper.extractLongNamed(tenureInMonthsParamName, element);
|
||||||
Long interestCompoundingPeriodInMonths = this.fromApiJsonHelper.extractLongNamed(interestCompoundingPeriodInMonthsParamName,
|
Long interestCompoundingPeriodInMonths = this.fromApiJsonHelper.extractLongNamed(interestCompoundingPeriodInMonthsParamName, element);
|
||||||
element);
|
|
||||||
BigDecimal maturityAmount = this.calculateInterestInternal(principalAmount, annualInterestRate, tenureInMonths,
|
// Optional params for exact calendar-based calculation
|
||||||
interestCompoundingPeriodInMonths);
|
LocalDate submittedOnDate = null;
|
||||||
String warning = "This is an approximate calculated amount - it may vary slightly when the account is created";
|
try {
|
||||||
|
final String dateStr = this.fromApiJsonHelper.extractStringNamed("submittedOnDate", element);
|
||||||
|
final String dateFormat = this.fromApiJsonHelper.extractStringNamed("dateFormat", element);
|
||||||
|
if (dateStr != null && dateFormat != null) {
|
||||||
|
submittedOnDate = LocalDate.parse(dateStr, java.time.format.DateTimeFormatter.ofPattern(dateFormat));
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
Integer daysInYear = null;
|
||||||
|
final Long daysInYearLong = this.fromApiJsonHelper.extractLongNamed("daysInYear", element);
|
||||||
|
if (daysInYearLong != null) daysInYear = daysInYearLong.intValue();
|
||||||
|
Long interestPostingPeriodInMonths = this.fromApiJsonHelper.extractLongNamed("interestPostingPeriodInMonths", element);
|
||||||
|
|
||||||
|
BigDecimal maturityAmount;
|
||||||
|
if (submittedOnDate != null && daysInYear != null && interestPostingPeriodInMonths != null) {
|
||||||
|
// Exact calendar-based calculation — same algorithm as account creation
|
||||||
|
final LocalDate maturityDate = submittedOnDate.plusMonths(tenureInMonths);
|
||||||
|
maturityAmount = this.calculateExact(principalAmount, annualInterestRate, submittedOnDate, maturityDate,
|
||||||
|
interestCompoundingPeriodInMonths, interestPostingPeriodInMonths, daysInYear);
|
||||||
|
} else {
|
||||||
|
maturityAmount = this.calculateInterestInternal(principalAmount, annualInterestRate, tenureInMonths,
|
||||||
|
interestCompoundingPeriodInMonths);
|
||||||
|
}
|
||||||
|
|
||||||
HashMap result = new HashMap<>();
|
HashMap result = new HashMap<>();
|
||||||
result.put("maturityAmount", maturityAmount);
|
result.put("maturityAmount", maturityAmount);
|
||||||
result.put("warning", warning);
|
result.put("totalInterest", maturityAmount.subtract(principalAmount).setScale(2, RoundingMode.HALF_UP));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exact calendar-based FD maturity calculation — replicates the PostingPeriod engine
|
||||||
|
* used during actual account creation/activation. Uses actual days per month.
|
||||||
|
*/
|
||||||
|
public BigDecimal calculateExact(final BigDecimal principal, final BigDecimal annualRate,
|
||||||
|
final LocalDate submittedOnDate, final LocalDate maturityDate,
|
||||||
|
final long compoundingMonths, final long postingMonths, final int daysInYear) {
|
||||||
|
final MathContext mc = MoneyHelper.getMathContext();
|
||||||
|
BigDecimal balance = principal;
|
||||||
|
LocalDate periodStart = submittedOnDate;
|
||||||
|
|
||||||
|
while (periodStart.isBefore(maturityDate)) {
|
||||||
|
// Determine end of this posting period (based on actual calendar)
|
||||||
|
LocalDate periodEnd;
|
||||||
|
if (postingMonths == 0) {
|
||||||
|
periodEnd = periodStart.plusDays(1);
|
||||||
|
} else {
|
||||||
|
periodEnd = periodStart.plusMonths(postingMonths);
|
||||||
|
}
|
||||||
|
if (periodEnd.isAfter(maturityDate)) {
|
||||||
|
periodEnd = maturityDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
final long daysInPeriod = ChronoUnit.DAYS.between(periodStart, periodEnd);
|
||||||
|
|
||||||
|
if (compoundingMonths == 0) {
|
||||||
|
// Daily compounding — exact: balance × (1 + r/D)^days
|
||||||
|
final double dailyRate = annualRate.doubleValue() / (daysInYear * 100.0);
|
||||||
|
final double multiplier = Math.pow(1.0 + dailyRate, daysInPeriod);
|
||||||
|
balance = balance.multiply(BigDecimal.valueOf(multiplier), mc);
|
||||||
|
} else {
|
||||||
|
// Periodic compounding — interest = balance × rate × days / (daysInYear × 100)
|
||||||
|
final BigDecimal interest = balance
|
||||||
|
.multiply(annualRate, mc)
|
||||||
|
.multiply(BigDecimal.valueOf(daysInPeriod), mc)
|
||||||
|
.divide(BigDecimal.valueOf((long) daysInYear * 100), mc);
|
||||||
|
balance = balance.add(interest);
|
||||||
|
}
|
||||||
|
|
||||||
|
periodStart = periodEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
return balance.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
}
|
||||||
|
|
||||||
public BigDecimal calculateInterestInternal(BigDecimal principalAmount, BigDecimal annualInterestRate, Long tenureInMonths,
|
public BigDecimal calculateInterestInternal(BigDecimal principalAmount, BigDecimal annualInterestRate, Long tenureInMonths,
|
||||||
Long interestCompoundingPeriodInMonths) {
|
Long interestCompoundingPeriodInMonths) {
|
||||||
|
if (interestCompoundingPeriodInMonths == null || interestCompoundingPeriodInMonths <= 0) {
|
||||||
|
// Daily compounding fallback: approximate with monthly
|
||||||
|
interestCompoundingPeriodInMonths = 1L;
|
||||||
|
}
|
||||||
BigDecimal numberOfCompoundingsPerAnnum = BigDecimal.valueOf(12).divide(BigDecimal.valueOf(interestCompoundingPeriodInMonths));
|
BigDecimal numberOfCompoundingsPerAnnum = BigDecimal.valueOf(12).divide(BigDecimal.valueOf(interestCompoundingPeriodInMonths));
|
||||||
Long totalNumberOfCompoundings = tenureInMonths / interestCompoundingPeriodInMonths;
|
Long totalNumberOfCompoundings = tenureInMonths / interestCompoundingPeriodInMonths;
|
||||||
MathContext mc = MoneyHelper.getMathContext();
|
MathContext mc = MoneyHelper.getMathContext();
|
||||||
|
|||||||
+18
-6
@@ -267,13 +267,25 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
|||||||
final SavingsAccountData accountData = this.jdbcTemplate.queryForObject(sql, this.savingAccountMapper,
|
final SavingsAccountData accountData = this.jdbcTemplate.queryForObject(sql, this.savingAccountMapper,
|
||||||
new Object[] { accountId }); // NOSONAR
|
new Object[] { accountId }); // NOSONAR
|
||||||
|
|
||||||
// Load joint holders
|
// Load joint holders with explicit camelCase keys (queryForList returns lowercase from MySQL)
|
||||||
if (accountData != null) {
|
if (accountData != null) {
|
||||||
final String jointSql = "SELECT jh.id as id, jh.client_id as clientId, jh.cif_number as cifNumber, "
|
final String jointSql = "SELECT jh.id, jh.client_id, jh.cif_number, jh.display_name, "
|
||||||
+ "jh.display_name as displayName, jh.share_percentage as sharePercentage, "
|
+ "jh.share_percentage, jh.signing_authority, jh.role, jh.is_primary, jh.is_mandatory "
|
||||||
+ "jh.signing_authority as signingAuthority, jh.role as role, jh.is_primary as isPrimary "
|
+ "FROM m_savings_account_joint_holders jh WHERE jh.savings_account_id = ? "
|
||||||
+ "FROM m_savings_account_joint_holders jh WHERE jh.savings_account_id = ?";
|
+ "ORDER BY jh.is_primary DESC, jh.id ASC";
|
||||||
final List<java.util.Map<String, Object>> jointHolders = this.jdbcTemplate.queryForList(jointSql, accountId);
|
final List<java.util.Map<String, Object>> jointHolders = this.jdbcTemplate.query(jointSql, (rs, rowNum) -> {
|
||||||
|
final java.util.Map<String, Object> h = new java.util.LinkedHashMap<>();
|
||||||
|
h.put("id", rs.getLong("id"));
|
||||||
|
h.put("clientId", rs.getLong("client_id"));
|
||||||
|
h.put("cifNumber", rs.getString("cif_number"));
|
||||||
|
h.put("displayName", rs.getString("display_name"));
|
||||||
|
h.put("sharePercentage", rs.getBigDecimal("share_percentage"));
|
||||||
|
h.put("signingAuthority", rs.getString("signing_authority"));
|
||||||
|
h.put("role", rs.getString("role"));
|
||||||
|
h.put("isPrimary", rs.getBoolean("is_primary"));
|
||||||
|
h.put("isMandatory", rs.getBoolean("is_mandatory"));
|
||||||
|
return h;
|
||||||
|
}, accountId);
|
||||||
if (!jointHolders.isEmpty()) {
|
if (!jointHolders.isEmpty()) {
|
||||||
accountData.setJointHolders(jointHolders);
|
accountData.setJointHolders(jointHolders);
|
||||||
}
|
}
|
||||||
|
|||||||
+10
@@ -386,6 +386,16 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
|||||||
this.savingAccountRepository.saveAndFlush(account);
|
this.savingAccountRepository.saveAndFlush(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Replace nominees if provided in the modify payload
|
||||||
|
final com.google.gson.JsonElement parsedJson = command.parsedJson();
|
||||||
|
if (parsedJson != null && parsedJson.isJsonObject()) {
|
||||||
|
final com.google.gson.JsonObject jsonObj = parsedJson.getAsJsonObject();
|
||||||
|
if (jsonObj.has("nominees") && !jsonObj.get("nominees").isJsonNull()) {
|
||||||
|
clientNomineeWritePlatformService.replaceNomineesForAccount(
|
||||||
|
account.clientId(), account.getAccountNumber(), "SB", jsonObj.get("nominees"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withCommandId(command.commandId()) //
|
.withCommandId(command.commandId()) //
|
||||||
.withEntityId(savingsId) //
|
.withEntityId(savingsId) //
|
||||||
|
|||||||
+69
@@ -116,6 +116,28 @@ public final class FixedDepositAccountData extends DepositAccountData {
|
|||||||
private Boolean deceasedSettlement;
|
private Boolean deceasedSettlement;
|
||||||
private Boolean allowDebitTxnAfterDueDate;
|
private Boolean allowDebitTxnAfterDueDate;
|
||||||
|
|
||||||
|
// Joint holders for JOINT account status
|
||||||
|
private java.util.List<java.util.Map<String, Object>> jointHolders;
|
||||||
|
|
||||||
|
// Senior citizen
|
||||||
|
private Boolean isSeniorCitizen;
|
||||||
|
private java.math.BigDecimal seniorCitizenInterestRate;
|
||||||
|
|
||||||
|
// CBS account-level fields (stored per-account in m_savings_account)
|
||||||
|
private String accountStatus;
|
||||||
|
private String modeOfOperation;
|
||||||
|
private Long introducerClientId;
|
||||||
|
private String introducerName;
|
||||||
|
private String introducerCifNumber;
|
||||||
|
private String specialCategory;
|
||||||
|
private String weakerSection;
|
||||||
|
private String guardianName;
|
||||||
|
private String guardianCifNumber;
|
||||||
|
private String guardianRelationship;
|
||||||
|
private Long guardianClientId;
|
||||||
|
private java.time.LocalDate minorDateOfBirth;
|
||||||
|
private Long linkedAccountId;
|
||||||
|
|
||||||
// import fields
|
// import fields
|
||||||
private transient Integer rowIndex;
|
private transient Integer rowIndex;
|
||||||
private String dateFormat;
|
private String dateFormat;
|
||||||
@@ -206,6 +228,31 @@ public final class FixedDepositAccountData extends DepositAccountData {
|
|||||||
this.allowDebitTxnAfterDueDate = allowDebitTxnAfterDueDate;
|
this.allowDebitTxnAfterDueDate = allowDebitTxnAfterDueDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setJointHolders(java.util.List<java.util.Map<String, Object>> v) { this.jointHolders = v; }
|
||||||
|
|
||||||
|
public void setCbsAccountFields(final String accountStatus, final String modeOfOperation,
|
||||||
|
final Long introducerClientId, final String introducerName, final String introducerCifNumber,
|
||||||
|
final String specialCategory, final String weakerSection,
|
||||||
|
final String guardianName, final String guardianCifNumber, final String guardianRelationship,
|
||||||
|
final Long guardianClientId, final java.time.LocalDate minorDateOfBirth, final Long linkedAccountId,
|
||||||
|
final Boolean isSeniorCitizen, final java.math.BigDecimal seniorCitizenInterestRate) {
|
||||||
|
this.accountStatus = accountStatus;
|
||||||
|
this.modeOfOperation = modeOfOperation;
|
||||||
|
this.introducerClientId = introducerClientId;
|
||||||
|
this.introducerName = introducerName;
|
||||||
|
this.introducerCifNumber = introducerCifNumber;
|
||||||
|
this.specialCategory = specialCategory;
|
||||||
|
this.weakerSection = weakerSection;
|
||||||
|
this.guardianName = guardianName;
|
||||||
|
this.guardianCifNumber = guardianCifNumber;
|
||||||
|
this.guardianRelationship = guardianRelationship;
|
||||||
|
this.guardianClientId = guardianClientId;
|
||||||
|
this.minorDateOfBirth = minorDateOfBirth;
|
||||||
|
this.linkedAccountId = linkedAccountId;
|
||||||
|
this.isSeniorCitizen = isSeniorCitizen;
|
||||||
|
this.seniorCitizenInterestRate = seniorCitizenInterestRate;
|
||||||
|
}
|
||||||
|
|
||||||
public void copyCbsFieldsFrom(final FixedDepositAccountData src) {
|
public void copyCbsFieldsFrom(final FixedDepositAccountData src) {
|
||||||
if (src == null) {
|
if (src == null) {
|
||||||
return;
|
return;
|
||||||
@@ -250,6 +297,23 @@ public final class FixedDepositAccountData extends DepositAccountData {
|
|||||||
this.noPenaltyNomineeHeirClosure = src.noPenaltyNomineeHeirClosure;
|
this.noPenaltyNomineeHeirClosure = src.noPenaltyNomineeHeirClosure;
|
||||||
this.deceasedSettlement = src.deceasedSettlement;
|
this.deceasedSettlement = src.deceasedSettlement;
|
||||||
this.allowDebitTxnAfterDueDate = src.allowDebitTxnAfterDueDate;
|
this.allowDebitTxnAfterDueDate = src.allowDebitTxnAfterDueDate;
|
||||||
|
// CBS account-level fields (per-account, not product defaults)
|
||||||
|
this.accountStatus = src.accountStatus;
|
||||||
|
this.modeOfOperation = src.modeOfOperation;
|
||||||
|
this.introducerClientId = src.introducerClientId;
|
||||||
|
this.introducerName = src.introducerName;
|
||||||
|
this.introducerCifNumber = src.introducerCifNumber;
|
||||||
|
this.specialCategory = src.specialCategory;
|
||||||
|
this.weakerSection = src.weakerSection;
|
||||||
|
this.guardianName = src.guardianName;
|
||||||
|
this.guardianCifNumber = src.guardianCifNumber;
|
||||||
|
this.guardianRelationship = src.guardianRelationship;
|
||||||
|
this.guardianClientId = src.guardianClientId;
|
||||||
|
this.minorDateOfBirth = src.minorDateOfBirth;
|
||||||
|
this.linkedAccountId = src.linkedAccountId;
|
||||||
|
this.jointHolders = src.jointHolders;
|
||||||
|
this.isSeniorCitizen = src.isSeniorCitizen;
|
||||||
|
this.seniorCitizenInterestRate = src.seniorCitizenInterestRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
private FixedDepositAccountData(Long clientId, Long productId, Long fieldofficerId, LocalDate submittedOnDate,
|
private FixedDepositAccountData(Long clientId, Long productId, Long fieldofficerId, LocalDate submittedOnDate,
|
||||||
@@ -387,6 +451,11 @@ public final class FixedDepositAccountData extends DepositAccountData {
|
|||||||
linkedAccount, account.transferInterestToSavings, account.withHoldTax, account.taxGroup, account.maturityInstructionOptions,
|
linkedAccount, account.transferInterestToSavings, account.withHoldTax, account.taxGroup, account.maturityInstructionOptions,
|
||||||
account.transferToSavingsId, transferToSavingsAccount);
|
account.transferToSavingsId, transferToSavingsAccount);
|
||||||
result.copyCbsFieldsFrom(account);
|
result.copyCbsFieldsFrom(account);
|
||||||
|
// Merge accountTypeOptions and customerSegmentOptions from template (not in account data)
|
||||||
|
if (template != null && template != account) {
|
||||||
|
if (template.getAccountTypeOptions() != null) result.setAccountTypeOptions(template.getAccountTypeOptions());
|
||||||
|
if (template.getCustomerSegmentOptions() != null) result.setCustomerSegmentOptions(template.getCustomerSegmentOptions());
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+79
-4
@@ -84,6 +84,28 @@ public final class RecurringDepositAccountData extends DepositAccountData {
|
|||||||
private LocalDate submittedOnDate;
|
private LocalDate submittedOnDate;
|
||||||
private Long depositPeriodFrequencyId;
|
private Long depositPeriodFrequencyId;
|
||||||
|
|
||||||
|
// Joint holders for JOINT account status
|
||||||
|
private java.util.List<java.util.Map<String, Object>> jointHolders;
|
||||||
|
|
||||||
|
// Senior citizen
|
||||||
|
private Boolean isSeniorCitizen;
|
||||||
|
private java.math.BigDecimal seniorCitizenInterestRate;
|
||||||
|
|
||||||
|
// CBS account-level fields (per-account values)
|
||||||
|
private String accountStatus;
|
||||||
|
private String modeOfOperation;
|
||||||
|
private Long introducerClientId;
|
||||||
|
private String introducerName;
|
||||||
|
private String introducerCifNumber;
|
||||||
|
private String specialCategory;
|
||||||
|
private String weakerSection;
|
||||||
|
private String guardianName;
|
||||||
|
private String guardianCifNumber;
|
||||||
|
private String guardianRelationship;
|
||||||
|
private Long guardianClientId;
|
||||||
|
private java.time.LocalDate minorDateOfBirth;
|
||||||
|
private Long linkedAccountId;
|
||||||
|
|
||||||
// CBS product fields (populated from product template)
|
// CBS product fields (populated from product template)
|
||||||
private String accountType;
|
private String accountType;
|
||||||
private String customerSegment;
|
private String customerSegment;
|
||||||
@@ -133,6 +155,31 @@ public final class RecurringDepositAccountData extends DepositAccountData {
|
|||||||
this.customerSegmentOptions = customerSegmentOptions;
|
this.customerSegmentOptions = customerSegmentOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setJointHolders(java.util.List<java.util.Map<String, Object>> v) { this.jointHolders = v; }
|
||||||
|
|
||||||
|
public void setCbsAccountFields(final String accountStatus, final String modeOfOperation,
|
||||||
|
final Long introducerClientId, final String introducerName, final String introducerCifNumber,
|
||||||
|
final String specialCategory, final String weakerSection,
|
||||||
|
final String guardianName, final String guardianCifNumber, final String guardianRelationship,
|
||||||
|
final Long guardianClientId, final java.time.LocalDate minorDateOfBirth, final Long linkedAccountId,
|
||||||
|
final Boolean isSeniorCitizen, final java.math.BigDecimal seniorCitizenInterestRate) {
|
||||||
|
this.accountStatus = accountStatus;
|
||||||
|
this.modeOfOperation = modeOfOperation;
|
||||||
|
this.introducerClientId = introducerClientId;
|
||||||
|
this.introducerName = introducerName;
|
||||||
|
this.introducerCifNumber = introducerCifNumber;
|
||||||
|
this.specialCategory = specialCategory;
|
||||||
|
this.weakerSection = weakerSection;
|
||||||
|
this.guardianName = guardianName;
|
||||||
|
this.guardianCifNumber = guardianCifNumber;
|
||||||
|
this.guardianRelationship = guardianRelationship;
|
||||||
|
this.guardianClientId = guardianClientId;
|
||||||
|
this.minorDateOfBirth = minorDateOfBirth;
|
||||||
|
this.linkedAccountId = linkedAccountId;
|
||||||
|
this.isSeniorCitizen = isSeniorCitizen;
|
||||||
|
this.seniorCitizenInterestRate = seniorCitizenInterestRate;
|
||||||
|
}
|
||||||
|
|
||||||
public void copyCbsFieldsFrom(final RecurringDepositAccountData src) {
|
public void copyCbsFieldsFrom(final RecurringDepositAccountData src) {
|
||||||
if (src == null) return;
|
if (src == null) return;
|
||||||
this.accountType = src.accountType;
|
this.accountType = src.accountType;
|
||||||
@@ -174,6 +221,23 @@ public final class RecurringDepositAccountData extends DepositAccountData {
|
|||||||
this.noPenaltyNomineeHeirClosure = src.noPenaltyNomineeHeirClosure;
|
this.noPenaltyNomineeHeirClosure = src.noPenaltyNomineeHeirClosure;
|
||||||
this.deceasedSettlement = src.deceasedSettlement;
|
this.deceasedSettlement = src.deceasedSettlement;
|
||||||
this.allowDebitTxnAfterDueDate = src.allowDebitTxnAfterDueDate;
|
this.allowDebitTxnAfterDueDate = src.allowDebitTxnAfterDueDate;
|
||||||
|
// CBS account-level fields (per-account, not product defaults)
|
||||||
|
this.accountStatus = src.accountStatus;
|
||||||
|
this.modeOfOperation = src.modeOfOperation;
|
||||||
|
this.introducerClientId = src.introducerClientId;
|
||||||
|
this.introducerName = src.introducerName;
|
||||||
|
this.introducerCifNumber = src.introducerCifNumber;
|
||||||
|
this.specialCategory = src.specialCategory;
|
||||||
|
this.weakerSection = src.weakerSection;
|
||||||
|
this.guardianName = src.guardianName;
|
||||||
|
this.guardianCifNumber = src.guardianCifNumber;
|
||||||
|
this.guardianRelationship = src.guardianRelationship;
|
||||||
|
this.guardianClientId = src.guardianClientId;
|
||||||
|
this.minorDateOfBirth = src.minorDateOfBirth;
|
||||||
|
this.linkedAccountId = src.linkedAccountId;
|
||||||
|
this.jointHolders = src.jointHolders;
|
||||||
|
this.isSeniorCitizen = src.isSeniorCitizen;
|
||||||
|
this.seniorCitizenInterestRate = src.seniorCitizenInterestRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCbsProductFields(String accountType, String customerSegment, String productCode,
|
public void setCbsProductFields(String accountType, String customerSegment, String productCode,
|
||||||
@@ -340,7 +404,7 @@ public final class RecurringDepositAccountData extends DepositAccountData {
|
|||||||
public static RecurringDepositAccountData withInterestChartAndRecurringDetails(final RecurringDepositAccountData account,
|
public static RecurringDepositAccountData withInterestChartAndRecurringDetails(final RecurringDepositAccountData account,
|
||||||
final DepositAccountInterestRateChartData accountChart, final Integer recurringFrequency,
|
final DepositAccountInterestRateChartData accountChart, final Integer recurringFrequency,
|
||||||
final EnumOptionData recurringFrequencyType) {
|
final EnumOptionData recurringFrequencyType) {
|
||||||
return new RecurringDepositAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
|
final RecurringDepositAccountData result = new RecurringDepositAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
|
||||||
account.clientId, account.clientName, account.depositProductId, account.depositProductName, account.fieldOfficerId,
|
account.clientId, account.clientName, account.depositProductId, account.depositProductName, account.fieldOfficerId,
|
||||||
account.fieldOfficerName, account.status, account.timeline, account.currency, account.nominalAnnualInterestRate,
|
account.fieldOfficerName, account.status, account.timeline, account.currency, account.nominalAnnualInterestRate,
|
||||||
account.interestCompoundingPeriodType, account.interestPostingPeriodType, account.interestCalculationType,
|
account.interestCompoundingPeriodType, account.interestPostingPeriodType, account.interestCalculationType,
|
||||||
@@ -360,6 +424,8 @@ public final class RecurringDepositAccountData extends DepositAccountData {
|
|||||||
account.noOfOverdueInstallments, account.isMandatoryDeposit, account.allowWithdrawal,
|
account.noOfOverdueInstallments, account.isMandatoryDeposit, account.allowWithdrawal,
|
||||||
account.adjustAdvanceTowardsFuturePayments, account.isCalendarInherited, recurringFrequency, recurringFrequencyType,
|
account.adjustAdvanceTowardsFuturePayments, account.isCalendarInherited, recurringFrequency, recurringFrequencyType,
|
||||||
account.withHoldTax, account.taxGroup);
|
account.withHoldTax, account.taxGroup);
|
||||||
|
result.copyCbsFieldsFrom(account);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RecurringDepositAccountData withTemplateOptions(final RecurringDepositAccountData account,
|
public static RecurringDepositAccountData withTemplateOptions(final RecurringDepositAccountData account,
|
||||||
@@ -386,7 +452,7 @@ public final class RecurringDepositAccountData extends DepositAccountData {
|
|||||||
preClosurePenalInterestOnTypeOptions, periodFrequencyTypeOptions);
|
preClosurePenalInterestOnTypeOptions, periodFrequencyTypeOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new RecurringDepositAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
|
final RecurringDepositAccountData result = new RecurringDepositAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
|
||||||
account.clientId, account.clientName, account.depositProductId, account.depositProductName, account.fieldOfficerId,
|
account.clientId, account.clientName, account.depositProductId, account.depositProductName, account.fieldOfficerId,
|
||||||
account.fieldOfficerName, account.status, account.timeline, account.currency, account.nominalAnnualInterestRate,
|
account.fieldOfficerName, account.status, account.timeline, account.currency, account.nominalAnnualInterestRate,
|
||||||
account.interestCompoundingPeriodType, account.interestPostingPeriodType, account.interestCalculationType,
|
account.interestCompoundingPeriodType, account.interestPostingPeriodType, account.interestCalculationType,
|
||||||
@@ -406,6 +472,11 @@ public final class RecurringDepositAccountData extends DepositAccountData {
|
|||||||
account.noOfOverdueInstallments, account.isMandatoryDeposit, account.allowWithdrawal,
|
account.noOfOverdueInstallments, account.isMandatoryDeposit, account.allowWithdrawal,
|
||||||
account.adjustAdvanceTowardsFuturePayments, account.isCalendarInherited, account.recurringFrequency,
|
account.adjustAdvanceTowardsFuturePayments, account.isCalendarInherited, account.recurringFrequency,
|
||||||
account.recurringFrequencyType, account.withHoldTax, account.taxGroup);
|
account.recurringFrequencyType, account.withHoldTax, account.taxGroup);
|
||||||
|
result.copyCbsFieldsFrom(account);
|
||||||
|
// Merge accountTypeOptions and customerSegmentOptions from template
|
||||||
|
if (template.getAccountTypeOptions() != null) result.setAccountTypeOptions(template.getAccountTypeOptions());
|
||||||
|
if (template.getCustomerSegmentOptions() != null) result.setCustomerSegmentOptions(template.getCustomerSegmentOptions());
|
||||||
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,7 +491,7 @@ public final class RecurringDepositAccountData extends DepositAccountData {
|
|||||||
final Collection<ChargeData> chargeOptions, final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions,
|
final Collection<ChargeData> chargeOptions, final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions,
|
||||||
final Collection<EnumOptionData> periodFrequencyTypeOptions) {
|
final Collection<EnumOptionData> periodFrequencyTypeOptions) {
|
||||||
|
|
||||||
return new RecurringDepositAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
|
final RecurringDepositAccountData r2 = new RecurringDepositAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
|
||||||
account.clientId, account.clientName, account.depositProductId, account.depositProductName, account.fieldOfficerId,
|
account.clientId, account.clientName, account.depositProductId, account.depositProductName, account.fieldOfficerId,
|
||||||
account.fieldOfficerName, account.status, account.timeline, account.currency, account.nominalAnnualInterestRate,
|
account.fieldOfficerName, account.status, account.timeline, account.currency, account.nominalAnnualInterestRate,
|
||||||
account.interestCompoundingPeriodType, account.interestPostingPeriodType, account.interestCalculationType,
|
account.interestCompoundingPeriodType, account.interestPostingPeriodType, account.interestCalculationType,
|
||||||
@@ -439,6 +510,8 @@ public final class RecurringDepositAccountData extends DepositAccountData {
|
|||||||
account.noOfOverdueInstallments, account.isMandatoryDeposit, account.allowWithdrawal,
|
account.noOfOverdueInstallments, account.isMandatoryDeposit, account.allowWithdrawal,
|
||||||
account.adjustAdvanceTowardsFuturePayments, account.isCalendarInherited, account.recurringFrequency,
|
account.adjustAdvanceTowardsFuturePayments, account.isCalendarInherited, account.recurringFrequency,
|
||||||
account.recurringFrequencyType, account.withHoldTax, account.taxGroup);
|
account.recurringFrequencyType, account.withHoldTax, account.taxGroup);
|
||||||
|
r2.copyCbsFieldsFrom(account);
|
||||||
|
return r2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RecurringDepositAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId,
|
public static RecurringDepositAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId,
|
||||||
@@ -629,7 +702,7 @@ public final class RecurringDepositAccountData extends DepositAccountData {
|
|||||||
final Collection<EnumOptionData> onAccountClosureOptions, final Collection<PaymentTypeData> paymentTypeOptions,
|
final Collection<EnumOptionData> onAccountClosureOptions, final Collection<PaymentTypeData> paymentTypeOptions,
|
||||||
final Collection<SavingsAccountData> savingsAccountDatas) {
|
final Collection<SavingsAccountData> savingsAccountDatas) {
|
||||||
|
|
||||||
return new RecurringDepositAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
|
final RecurringDepositAccountData closureResult = new RecurringDepositAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
|
||||||
account.clientId, account.clientName, account.depositProductId, account.depositProductName, account.fieldOfficerId,
|
account.clientId, account.clientName, account.depositProductId, account.depositProductName, account.fieldOfficerId,
|
||||||
account.fieldOfficerName, account.status, account.timeline, account.currency, account.nominalAnnualInterestRate,
|
account.fieldOfficerName, account.status, account.timeline, account.currency, account.nominalAnnualInterestRate,
|
||||||
account.interestCompoundingPeriodType, account.interestPostingPeriodType, account.interestCalculationType,
|
account.interestCompoundingPeriodType, account.interestPostingPeriodType, account.interestCalculationType,
|
||||||
@@ -649,6 +722,8 @@ public final class RecurringDepositAccountData extends DepositAccountData {
|
|||||||
account.noOfOverdueInstallments, account.isMandatoryDeposit, account.allowWithdrawal,
|
account.noOfOverdueInstallments, account.isMandatoryDeposit, account.allowWithdrawal,
|
||||||
account.adjustAdvanceTowardsFuturePayments, account.isCalendarInherited, account.recurringFrequency,
|
account.adjustAdvanceTowardsFuturePayments, account.isCalendarInherited, account.recurringFrequency,
|
||||||
account.recurringFrequencyType, account.withHoldTax, account.taxGroup);
|
account.recurringFrequencyType, account.withHoldTax, account.taxGroup);
|
||||||
|
closureResult.copyCbsFieldsFrom(account);
|
||||||
|
return closureResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RecurringDepositAccountData(final Long id, final String accountNo, final String externalId, final Long groupId,
|
private RecurringDepositAccountData(final Long id, final String accountNo, final String externalId, final Long groupId,
|
||||||
|
|||||||
Reference in New Issue
Block a user