rd account save api update

This commit is contained in:
Nitesh Yadav
2026-04-30 16:12:17 +05:30
parent 045437fcb8
commit be220d8778
17 changed files with 64864 additions and 95772 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -230,12 +230,14 @@ public class RecurringDepositAccount extends SavingsAccount {
}
final BigDecimal depositAmount = accountTermAndPreClosure.depositAmount();
BigDecimal applicableInterestRate = this.chart.getApplicableInterestRate(depositAmount, depositStartDate(), depositCloseDate,
this.client);
BigDecimal applicableInterestRate = BigDecimal.ZERO;
if (this.chart != null) {
applicableInterestRate = this.chart.getApplicableInterestRate(depositAmount, depositStartDate(), depositCloseDate, this.client);
if (applyPreMaturePenalty) {
applicableInterestRate = applicableInterestRate.subtract(penalInterest);
applicableInterestRate = applicableInterestRate.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : applicableInterestRate;
if (applyPreMaturePenalty) {
applicableInterestRate = applicableInterestRate.subtract(penalInterest);
applicableInterestRate = applicableInterestRate.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : applicableInterestRate;
}
}
this.nominalAnnualInterestRate = applicableInterestRate;
@@ -1070,10 +1072,8 @@ public class RecurringDepositAccount extends SavingsAccount {
.failWithCodeNoParameterAddedToErrorCode("no.applicable.interest.rate.is.found.based.on.amount.and.deposit.period");
}
} else if (this.nominalAnnualInterestRate == null || this.nominalAnnualInterestRate.compareTo(BigDecimal.ZERO) == 0) {
baseDataValidator.reset().parameter(DepositsApiConstants.nominalAnnualInterestRateParamName).value(nominalAnnualInterestRate)
.failWithCodeNoParameterAddedToErrorCode("interest.chart.or.nominal.interest.rate.required");
}
// CBS: chart is optional — CBS base interest rate chart is used instead
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
@@ -367,7 +367,7 @@ public class SavingsAccountAssembler {
private static final Gson GSON = new Gson();
private void applyCbsFields(final JsonCommand command, final JsonElement element, final SavingsAccount account) {
public void applyCbsFields(final JsonCommand command, final JsonElement element, final SavingsAccount account) {
// Product classification
final String cbsAccountType = this.fromApiJsonHelper.extractStringNamed(accountTypeParamName, element);
if (cbsAccountType != null) account.setCbsAccountType(cbsAccountType);
@@ -458,8 +458,9 @@ public class SavingsAccountAssembler {
role = isPrimary ? "Primary Account Holder" : "Co-Holder";
}
final boolean isMandatory = h.has("isMandatory") && h.get("isMandatory").getAsBoolean();
holders.add(new SavingsAccountJointHolder(account, clientId, cifNumber, displayName,
sharePercentage, signingAuthority, role, isPrimary));
sharePercentage, signingAuthority, role, isPrimary, isMandatory));
}
account.getJointHolders().clear();
account.getJointHolders().addAll(holders);
@@ -88,10 +88,12 @@ public class CurrentAccountReadPlatformServiceImpl implements CurrentAccountRead
out.put("groupId", row.get("group_id"));
out.put("productId", row.get("product_id"));
out.put("productName", row.get("product_name"));
out.put("currentAccountProductName", row.get("product_name"));
out.put("shortProductName", row.get("product_short_name"));
out.put("officeId", row.get("office_id"));
out.put("officeName", row.get("office_name"));
out.put("staffId", row.get("staff_id"));
out.put("fieldOfficerId", row.get("staff_id"));
out.put("fieldOfficerName", row.get("staff_name"));
// status
@@ -234,6 +236,12 @@ public class CurrentAccountReadPlatformServiceImpl implements CurrentAccountRead
};
s.put("code", "SavingsAccountSubStatusEnum." + value.replace(" ", ""));
s.put("value", value);
s.put("none", subStatusEnum == 0);
s.put("inactive", subStatusEnum == 100);
s.put("dormant", subStatusEnum == 200);
s.put("block", subStatusEnum == 300);
s.put("blockDebit", subStatusEnum == 400);
s.put("blockCredit", subStatusEnum == 500);
return s;
}
@@ -130,6 +130,9 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri
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());
}
// UI may send "introducerClientId" or "introducerId"
Long introducerClientId = getLong(json, "introducerClientId");
if (introducerClientId == null) introducerClientId = getLong(json, "introducerId");
@@ -324,6 +327,11 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri
if (jo.has("displayName") && !jo.get("displayName").isJsonNull()) holder.setDisplayName(jo.get("displayName").getAsString());
if (jo.has("signingAuthority") && !jo.get("signingAuthority").isJsonNull()) holder.setSigningAuthority(jo.get("signingAuthority").getAsString());
if (jo.has("role") && !jo.get("role").isJsonNull()) holder.setRole(jo.get("role").getAsString());
if (jo.has("sharePercentage") && !jo.get("sharePercentage").isJsonNull()) {
try { holder.setSharePercentage(jo.get("sharePercentage").getAsBigDecimal()); } catch (Exception ignored) {}
}
if (jo.has("isPrimary") && !jo.get("isPrimary").isJsonNull()) holder.setPrimary(jo.get("isPrimary").getAsBoolean());
if (jo.has("isMandatory") && !jo.get("isMandatory").isJsonNull()) holder.setMandatory(jo.get("isMandatory").getAsBoolean());
account.getJointHolders().add(holder);
}
}
@@ -337,6 +345,10 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri
if (cid != null) partner.setClientId(cid);
if (jo.has("clientCif") && !jo.get("clientCif").isJsonNull()) partner.setClientCif(jo.get("clientCif").getAsString());
if (jo.has("clientName") && !jo.get("clientName").isJsonNull()) partner.setClientName(jo.get("clientName").getAsString());
if (jo.has("sharePercentage") && !jo.get("sharePercentage").isJsonNull()) {
try { partner.setSharePercentage(jo.get("sharePercentage").getAsBigDecimal()); } catch (Exception ignored) {}
}
if (jo.has("isMandatory") && !jo.get("isMandatory").isJsonNull()) partner.setMandatory(jo.get("isMandatory").getAsBoolean());
account.getPartners().add(partner);
}
}
@@ -143,7 +143,7 @@ public class DepositAccountInterestRateChartReadPlatformServiceImpl implements D
return preparedStatement;
}, this.chartExtractor);
if (chartDatas == null || chartDatas.isEmpty()) {
throw new DepositAccountInterestRateChartNotFoundException(accountId);
return null;
}
return chartDatas.iterator().next();
@@ -275,10 +275,15 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
} else if (depositAccountType.isRecurringDeposit()) {
CalendarData calendar = this.calendarReadPlatformService.retrieveCollctionCalendarByEntity(accountId,
CalendarEntityType.SAVINGS.getValue());
final Integer frequency = calendar.getInterval() == -1 ? 1 : calendar.getInterval();
final CalendarFrequencyType calendarFrequencyType = CalendarFrequencyType.fromInt(calendar.getFrequency().getId().intValue());
final PeriodFrequencyType periodFrequencyType = CalendarFrequencyType.from(calendarFrequencyType);
final EnumOptionData frequencyType = CommonEnumerations.termFrequencyType(periodFrequencyType, "recurring.deposit.frequency.");
Integer frequency = 1;
EnumOptionData frequencyType = null;
if (calendar != null) {
frequency = calendar.getInterval() == -1 ? 1 : calendar.getInterval();
final CalendarFrequencyType calendarFrequencyType = CalendarFrequencyType
.fromInt(calendar.getFrequency().getId().intValue());
final PeriodFrequencyType periodFrequencyType = CalendarFrequencyType.from(calendarFrequencyType);
frequencyType = CommonEnumerations.termFrequencyType(periodFrequencyType, "recurring.deposit.frequency.");
}
depositAccount = RecurringDepositAccountData.withInterestChartAndRecurringDetails((RecurringDepositAccountData) depositAccount,
chart, frequency, frequencyType);
}
@@ -89,6 +89,7 @@ import org.apache.fineract.portfolio.savings.domain.RecurringDepositAccountRepos
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountCharge;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountChargeAssembler;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrapper;
import org.apache.fineract.portfolio.savings.domain.SavingsProduct;
import org.apache.fineract.portfolio.savings.domain.SavingsProductRepository;
@@ -121,6 +122,7 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
private final ConfigurationDomainService configurationDomainService;
private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository;
private final BusinessEventNotifierService businessEventNotifierService;
private final SavingsAccountAssembler savingsAccountAssembler;
/*
* Guaranteed to throw an exception no matter what the data integrity issue is.
@@ -226,6 +228,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
final RecurringDepositAccount account = (RecurringDepositAccount) this.depositAccountAssembler.assembleFrom(command,
submittedBy, DepositAccountType.RECURRING_DEPOSIT);
this.savingsAccountAssembler.applyCbsFields(command, command.parsedJson(), account);
this.recurringDepositAccountRepository.save(account);
if (account.isAccountNumberRequiresAutoGeneration()) {
@@ -798,6 +798,9 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
sqlBuilder.append("sa.linked_account_id as linkedAccountId, ");
sqlBuilder.append("sa.linked_account_type as linkedAccountType, ");
sqlBuilder.append("sa.linked_account_no as linkedAccountNo, ");
sqlBuilder.append("sp.balance_swap_option as balanceSwapOption, ");
sqlBuilder.append("sp.msme as msme, ");
sqlBuilder.append("sp.auto_debit_facility as autoDebitFacility, ");
// Facility config fields
sqlBuilder.append("safc.atm_facility as atmFacility, ");
sqlBuilder.append("safc.atm_withdrawal_facility as atmWithdrawalFacility, ");
@@ -1049,6 +1052,9 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
accountData.setLinkedAccountId(JdbcSupport.getLong(rs, "linkedAccountId"));
accountData.setLinkedAccountType(rs.getString("linkedAccountType"));
accountData.setLinkedAccountNo(rs.getString("linkedAccountNo"));
accountData.setBalanceSwapOption(rs.getObject("balanceSwapOption") != null ? rs.getBoolean("balanceSwapOption") : null);
accountData.setMsme(rs.getObject("msme") != null ? rs.getBoolean("msme") : null);
accountData.setAutoDebitFacility(rs.getObject("autoDebitFacility") != null ? rs.getBoolean("autoDebitFacility") : null);
// Nominee as parsed map
final String nomineeDataStr = rs.getString("nomineeData");
@@ -277,13 +277,13 @@ public class SavingsConfiguration {
SavingsAccountChargeAssembler savingsAccountChargeAssembler, AccountAssociationsRepository accountAssociationsRepository,
FromJsonHelper fromJsonHelper, CalendarInstanceRepository calendarInstanceRepository,
ConfigurationDomainService configurationDomainService, AccountNumberFormatRepositoryWrapper accountNumberFormatRepository,
BusinessEventNotifierService businessEventNotifierService) {
BusinessEventNotifierService businessEventNotifierService, SavingsAccountAssembler savingsAccountAssembler) {
return new DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl(context, savingAccountRepository,
fixedDepositAccountRepository, recurringDepositAccountRepository, depositAccountAssembler, depositAccountDataValidator,
accountNumberGenerator, clientRepository, groupRepository, savingsProductRepository, noteRepository, staffRepository,
savingsAccountApplicationTransitionApiJsonValidator, savingsAccountChargeAssembler, accountAssociationsRepository,
fromJsonHelper, calendarInstanceRepository, configurationDomainService, accountNumberFormatRepository,
businessEventNotifierService);
businessEventNotifierService, savingsAccountAssembler);
}
@Bean
@@ -285,4 +285,5 @@
<include file="parts/0273_add_gl_account_id_to_current_product.xml" relativeToChangelogFile="true"/>
<include file="parts/0276_create_current_account_tables.xml" relativeToChangelogFile="true"/>
<include file="parts/0277_fix_current_account_audit_columns.xml" relativeToChangelogFile="true"/>
<include file="parts/0278_add_is_mandatory_to_joint_holder.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
@@ -0,0 +1,22 @@
<?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.3.xsd">
<changeSet id="0278_add_is_mandatory_to_joint_holder" author="system">
<addColumn tableName="m_current_account_joint_holder">
<column name="is_mandatory" type="boolean" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
</addColumn>
</changeSet>
<changeSet id="0278b_add_is_mandatory_to_savings_joint_holder" author="system">
<addColumn tableName="m_savings_account_joint_holders">
<column name="is_mandatory" type="boolean" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
</addColumn>
</changeSet>
</databaseChangeLog>