feat: fix standing instructions GL accounting for current account transfers
- AccountTransfersWritePlatformServiceImpl:
* Direct GL posting for current↔savings/current transfers:
DR debit-side account GL (with correct account entity_id)
CR credit-side account GL (with correct account entity_id)
* Prefix current account txn_id with CA (not C) so
JournalEntryReadPlatformServiceImpl joins m_current_account
and shows correct current account number on GL entries
* Suppress redundant savings deposit/withdrawal GL entries
(skipAccountingPostings=true) when current account handles
the full double-entry directly
* Separate performCurrentWithdrawalForLoan for Current→Loan
transfers (loan domain service handles the other GL leg)
* Reuse existing AccountTransferDetails for SI recurring runs
so transactions appear in list-account-transactions history
- SavingsAccountDomainService / SavingsAccountDomainServiceJpa:
* New handleDeposit overload with skipAccountingPostings flag
* handleWithdrawal respects SavingsTransactionBooleanValues
.isSkipAccountingPostings() to suppress redundant GL entries
- SavingsTransactionBooleanValues:
* Added skipAccountingPostings field + overloaded constructor
- AccountingProcessorHelper:
* New createDirectTransferJournalEntriesForSavings() method
creates DR and CR entries with separate productId/entityId
so each GL line shows the correct account number
- JournalEntryReadPlatformServiceImpl:
* Join both m_savings_account and m_current_account always
* COALESCE(ca.account_no, sa.account_no) to resolve correct
account number regardless of transaction_id prefix
- ExecuteStandingInstructionsTasklet:
* Load existing AccountTransferDetails via repository so
subsequent SI runs link to the same transfer detail record
- ExecuteStandingInstructionsConfig / AccountConfiguration:
* Wire AccountTransferDetailRepository and
AccountingProcessorHelper into the relevant beans
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
2251fd2259
commit
7d4f409202
+21
@@ -600,6 +600,27 @@ public class AccountingProcessorHelper {
|
|||||||
createCreditJournalEntryForSavings(office, currencyCode, creditAccount, savingsId, transactionId, transactionDate, amount);
|
createCreditJournalEntryForSavings(office, currencyCode, creditAccount, savingsId, transactionId, transactionDate, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a direct transfer journal entry between two savings-type accounts (savings or current),
|
||||||
|
* each with their own product GL mapping and entity ID so the correct account number appears per entry.
|
||||||
|
*
|
||||||
|
* @param debitProductId product ID whose SAVINGS_CONTROL GL is debited
|
||||||
|
* @param debitEntityId entity (account) ID shown on the debit entry
|
||||||
|
* @param creditProductId product ID whose SAVINGS_CONTROL GL is credited
|
||||||
|
* @param creditEntityId entity (account) ID shown on the credit entry
|
||||||
|
*/
|
||||||
|
public void createDirectTransferJournalEntriesForSavings(final Office office, final String currencyCode,
|
||||||
|
final Long debitProductId, final Long debitEntityId,
|
||||||
|
final Long creditProductId, final Long creditEntityId,
|
||||||
|
final String transactionId, final LocalDate transactionDate, final BigDecimal amount) {
|
||||||
|
final GLAccount debitAccount = getLinkedGLAccountForSavingsProduct(debitProductId,
|
||||||
|
CashAccountsForSavings.SAVINGS_CONTROL.getValue(), null);
|
||||||
|
final GLAccount creditAccount = getLinkedGLAccountForSavingsProduct(creditProductId,
|
||||||
|
CashAccountsForSavings.SAVINGS_CONTROL.getValue(), null);
|
||||||
|
createDebitJournalEntryForSavings(office, currencyCode, debitAccount, debitEntityId, transactionId, transactionDate, amount);
|
||||||
|
createCreditJournalEntryForSavings(office, currencyCode, creditAccount, creditEntityId, transactionId, transactionDate, amount);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method that creates a pair of related Debits and Credits for Cash Based accounting.
|
* Convenience method that creates a pair of related Debits and Credits for Cash Based accounting.
|
||||||
*
|
*
|
||||||
|
|||||||
+3
-4
@@ -106,8 +106,7 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
|
|||||||
.append(" curr.display_symbol as currencyDisplaySymbol, curr.decimal_places as currencyDigits, curr.currency_multiplesof as inMultiplesOf, ")
|
.append(" curr.display_symbol as currencyDisplaySymbol, curr.decimal_places as currencyDigits, curr.currency_multiplesof as inMultiplesOf, ")
|
||||||
.append(" eao.external_id as externalAssetOwner, ")
|
.append(" eao.external_id as externalAssetOwner, ")
|
||||||
.append(" CASE ")
|
.append(" CASE ")
|
||||||
.append(" WHEN journalEntry.entity_type_enum = 2 AND journalEntry.transaction_id LIKE 'CA%' THEN ca.account_no ")
|
.append(" WHEN journalEntry.entity_type_enum = 2 THEN COALESCE(ca.account_no, sa.account_no) ")
|
||||||
.append(" WHEN journalEntry.entity_type_enum = 2 THEN sa.account_no ")
|
|
||||||
.append(" ELSE NULL ")
|
.append(" ELSE NULL ")
|
||||||
.append(" END as savingsAccountNo ");
|
.append(" END as savingsAccountNo ");
|
||||||
if (associationParametersData.isRunningBalanceRequired()) {
|
if (associationParametersData.isRunningBalanceRequired()) {
|
||||||
@@ -130,8 +129,8 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
|
|||||||
.append(" join m_currency curr on curr.code = journalEntry.currency_code ")
|
.append(" join m_currency curr on curr.code = journalEntry.currency_code ")
|
||||||
.append(" left join m_external_asset_owner_journal_entry_mapping eajem on eajem.journal_entry_id = journalEntry.id ")
|
.append(" left join m_external_asset_owner_journal_entry_mapping eajem on eajem.journal_entry_id = journalEntry.id ")
|
||||||
.append(" left join m_external_asset_owner eao on eao.id = eajem.owner_id ")
|
.append(" left join m_external_asset_owner eao on eao.id = eajem.owner_id ")
|
||||||
.append(" left join m_savings_account sa on sa.id = journalEntry.entity_id AND journalEntry.entity_type_enum = 2 AND journalEntry.transaction_id NOT LIKE 'CA%' ")
|
.append(" left join m_savings_account sa on sa.id = journalEntry.entity_id AND journalEntry.entity_type_enum = 2 ")
|
||||||
.append(" left join m_current_account ca on ca.id = journalEntry.entity_id AND journalEntry.entity_type_enum = 2 AND journalEntry.transaction_id LIKE 'CA%' ");
|
.append(" left join m_current_account ca on ca.id = journalEntry.entity_id AND journalEntry.entity_type_enum = 2 ");
|
||||||
if (associationParametersData.isTransactionDetailsRequired()) {
|
if (associationParametersData.isTransactionDetailsRequired()) {
|
||||||
sb.append(" left join m_loan_transaction as lt on journalEntry.loan_transaction_id = lt.id ")
|
sb.append(" left join m_loan_transaction as lt on journalEntry.loan_transaction_id = lt.id ")
|
||||||
.append(" left join m_savings_account_transaction as st on journalEntry.savings_transaction_id = st.id ")
|
.append(" left join m_savings_account_transaction as st on journalEntry.savings_transaction_id = st.id ")
|
||||||
|
|||||||
+4
-1
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.account.jobs.executestandinginstructions;
|
|||||||
|
|
||||||
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
|
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
|
||||||
import org.apache.fineract.infrastructure.jobs.service.JobName;
|
import org.apache.fineract.infrastructure.jobs.service.JobName;
|
||||||
|
import org.apache.fineract.portfolio.account.domain.AccountTransferDetailRepository;
|
||||||
import org.apache.fineract.portfolio.account.service.AccountTransfersWritePlatformService;
|
import org.apache.fineract.portfolio.account.service.AccountTransfersWritePlatformService;
|
||||||
import org.apache.fineract.portfolio.account.service.StandingInstructionReadPlatformService;
|
import org.apache.fineract.portfolio.account.service.StandingInstructionReadPlatformService;
|
||||||
import org.springframework.batch.core.Job;
|
import org.springframework.batch.core.Job;
|
||||||
@@ -49,6 +50,8 @@ public class ExecuteStandingInstructionsConfig {
|
|||||||
private DatabaseSpecificSQLGenerator sqlGenerator;
|
private DatabaseSpecificSQLGenerator sqlGenerator;
|
||||||
@Autowired
|
@Autowired
|
||||||
private AccountTransfersWritePlatformService accountTransfersWritePlatformService;
|
private AccountTransfersWritePlatformService accountTransfersWritePlatformService;
|
||||||
|
@Autowired
|
||||||
|
private AccountTransferDetailRepository accountTransferDetailRepository;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
protected Step executeStandingInstructionsStep() {
|
protected Step executeStandingInstructionsStep() {
|
||||||
@@ -65,6 +68,6 @@ public class ExecuteStandingInstructionsConfig {
|
|||||||
@Bean
|
@Bean
|
||||||
public ExecuteStandingInstructionsTasklet executeStandingInstructionsTasklet() {
|
public ExecuteStandingInstructionsTasklet executeStandingInstructionsTasklet() {
|
||||||
return new ExecuteStandingInstructionsTasklet(standingInstructionReadPlatformService, jdbcTemplate, sqlGenerator,
|
return new ExecuteStandingInstructionsTasklet(standingInstructionReadPlatformService, jdbcTemplate, sqlGenerator,
|
||||||
accountTransfersWritePlatformService);
|
accountTransfersWritePlatformService, accountTransferDetailRepository);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-1
@@ -34,6 +34,8 @@ import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
|
|||||||
import org.apache.fineract.portfolio.account.data.AccountTransferDTO;
|
import org.apache.fineract.portfolio.account.data.AccountTransferDTO;
|
||||||
import org.apache.fineract.portfolio.account.data.StandingInstructionData;
|
import org.apache.fineract.portfolio.account.data.StandingInstructionData;
|
||||||
import org.apache.fineract.portfolio.account.data.StandingInstructionDuesData;
|
import org.apache.fineract.portfolio.account.data.StandingInstructionDuesData;
|
||||||
|
import org.apache.fineract.portfolio.account.domain.AccountTransferDetailRepository;
|
||||||
|
import org.apache.fineract.portfolio.account.domain.AccountTransferDetails;
|
||||||
import org.apache.fineract.portfolio.account.domain.AccountTransferRecurrenceType;
|
import org.apache.fineract.portfolio.account.domain.AccountTransferRecurrenceType;
|
||||||
import org.apache.fineract.portfolio.account.domain.StandingInstructionStatus;
|
import org.apache.fineract.portfolio.account.domain.StandingInstructionStatus;
|
||||||
import org.apache.fineract.portfolio.account.domain.StandingInstructionType;
|
import org.apache.fineract.portfolio.account.domain.StandingInstructionType;
|
||||||
@@ -58,6 +60,7 @@ public class ExecuteStandingInstructionsTasklet implements Tasklet {
|
|||||||
private final JdbcTemplate jdbcTemplate;
|
private final JdbcTemplate jdbcTemplate;
|
||||||
private final DatabaseSpecificSQLGenerator sqlGenerator;
|
private final DatabaseSpecificSQLGenerator sqlGenerator;
|
||||||
private final AccountTransfersWritePlatformService accountTransfersWritePlatformService;
|
private final AccountTransfersWritePlatformService accountTransfersWritePlatformService;
|
||||||
|
private final AccountTransferDetailRepository accountTransferDetailRepository;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
|
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
|
||||||
@@ -105,10 +108,15 @@ public class ExecuteStandingInstructionsTasklet implements Tasklet {
|
|||||||
final SavingsAccount fromSavingsAccount = null;
|
final SavingsAccount fromSavingsAccount = null;
|
||||||
final boolean isRegularTransaction = true;
|
final boolean isRegularTransaction = true;
|
||||||
final boolean isExceptionForBalanceCheck = false;
|
final boolean isExceptionForBalanceCheck = false;
|
||||||
|
// Load existing AccountTransferDetails so transactions are linked to
|
||||||
|
// this standing instruction and appear in its transaction history
|
||||||
|
final AccountTransferDetails existingDetails = data.getAccountDetailId() != null
|
||||||
|
? accountTransferDetailRepository.findById(data.getAccountDetailId()).orElse(null)
|
||||||
|
: null;
|
||||||
AccountTransferDTO accountTransferDTO = new AccountTransferDTO(transactionDate, transactionAmount,
|
AccountTransferDTO accountTransferDTO = new AccountTransferDTO(transactionDate, transactionAmount,
|
||||||
data.fromAccountTypeEnum(), data.toAccountTypeEnum(), data.getFromAccount().getId(), data.getToAccount().getId(),
|
data.fromAccountTypeEnum(), data.toAccountTypeEnum(), data.getFromAccount().getId(), data.getToAccount().getId(),
|
||||||
data.getName() + " Standing instruction trasfer ", null, null, null, null, data.toTransferType(), null, null,
|
data.getName() + " Standing instruction trasfer ", null, null, null, null, data.toTransferType(), null, null,
|
||||||
data.transferTypeEnum().getValue(), null, null, ExternalId.empty(), null, null, fromSavingsAccount,
|
data.transferTypeEnum().getValue(), existingDetails, null, ExternalId.empty(), null, null, fromSavingsAccount,
|
||||||
isRegularTransaction, isExceptionForBalanceCheck);
|
isRegularTransaction, isExceptionForBalanceCheck);
|
||||||
final boolean transferCompleted = transferAmount(errors, accountTransferDTO, data.getId());
|
final boolean transferCompleted = transferAmount(errors, accountTransferDTO, data.getId());
|
||||||
|
|
||||||
|
|||||||
+147
-35
@@ -34,6 +34,9 @@ import java.util.Collection;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForSavings;
|
||||||
|
import org.apache.fineract.accounting.common.AccountingConstants.FinancialActivity;
|
||||||
|
import org.apache.fineract.accounting.journalentry.service.AccountingProcessorHelper;
|
||||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
||||||
@@ -96,6 +99,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
|||||||
private final FineractProperties fineractProperties;
|
private final FineractProperties fineractProperties;
|
||||||
private final CurrentAccountRepository currentAccountRepository;
|
private final CurrentAccountRepository currentAccountRepository;
|
||||||
private final CurrentAccountTransactionRepository currentAccountTransactionRepository;
|
private final CurrentAccountTransactionRepository currentAccountTransactionRepository;
|
||||||
|
private final AccountingProcessorHelper accountingProcessorHelper;
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
@@ -467,23 +471,29 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
|||||||
.assembleFrom(accountTransferDTO.getToAccountId(), backdatedTxnsAllowedTill);
|
.assembleFrom(accountTransferDTO.getToAccountId(), backdatedTxnsAllowedTill);
|
||||||
|
|
||||||
final CurrentAccountTransaction withdrawal = performCurrentWithdrawal(fromCurrentAccount,
|
final CurrentAccountTransaction withdrawal = performCurrentWithdrawal(fromCurrentAccount,
|
||||||
accountTransferDTO.getTransactionAmount(), accountTransferDTO.getTransactionDate());
|
accountTransferDTO.getTransactionAmount(), accountTransferDTO.getTransactionDate(),
|
||||||
|
toSavingsAccount.productId(), toSavingsAccount.getId());
|
||||||
|
|
||||||
|
// skipAccountingPostings=true: current account withdrawal leg (C-txn) already posts
|
||||||
|
// DR CURRENT ACCOUNT / CR SAVING INDIVIDUAL directly — each with its own account number.
|
||||||
|
// Savings deposit GL entries would produce a self-cancelling DR+CR on SAVING INDIVIDUAL — suppress them.
|
||||||
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount,
|
final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount,
|
||||||
accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(),
|
accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(),
|
||||||
accountTransferDTO.getTransactionAmount(), accountTransferDTO.getPaymentDetail(),
|
accountTransferDTO.getTransactionAmount(), accountTransferDTO.getPaymentDetail(),
|
||||||
isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill);
|
isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill, true);
|
||||||
|
|
||||||
final AccountTransferDetails newDetails = AccountTransferDetails.currentToSavingsTransfer(
|
if (accountTransferDetails == null) {
|
||||||
fromCurrentAccount.getOffice(), fromCurrentAccount.getClient(), fromCurrentAccount,
|
accountTransferDetails = AccountTransferDetails.currentToSavingsTransfer(
|
||||||
toSavingsAccount.office(), toSavingsAccount.getClient(), toSavingsAccount,
|
fromCurrentAccount.getOffice(), fromCurrentAccount.getClient(), fromCurrentAccount,
|
||||||
accountTransferDTO.getTransferType());
|
toSavingsAccount.office(), toSavingsAccount.getClient(), toSavingsAccount,
|
||||||
|
accountTransferDTO.getTransferType());
|
||||||
|
}
|
||||||
final Money amount = Money.of(toSavingsAccount.getCurrency(), accountTransferDTO.getTransactionAmount());
|
final Money amount = Money.of(toSavingsAccount.getCurrency(), accountTransferDTO.getTransactionAmount());
|
||||||
newDetails.addAccountTransferTransaction(AccountTransferTransaction.savingsToSavingsTransfer(
|
accountTransferDetails.addAccountTransferTransaction(AccountTransferTransaction.savingsToSavingsTransfer(
|
||||||
newDetails, null, deposit, accountTransferDTO.getTransactionDate(), amount,
|
accountTransferDetails, null, deposit, accountTransferDTO.getTransactionDate(), amount,
|
||||||
accountTransferDTO.getDescription()));
|
accountTransferDTO.getDescription()));
|
||||||
this.accountTransferDetailRepository.saveAndFlush(newDetails);
|
this.accountTransferDetailRepository.saveAndFlush(accountTransferDetails);
|
||||||
transferTransactionId = newDetails.getId();
|
transferTransactionId = accountTransferDetails.getId();
|
||||||
|
|
||||||
} else if (isSavingsToCurrentAccountTransfer(accountTransferDTO.getFromAccountType(), accountTransferDTO.getToAccountType())) {
|
} else if (isSavingsToCurrentAccountTransfer(accountTransferDTO.getFromAccountType(), accountTransferDTO.getToAccountType())) {
|
||||||
// --- Savings Account → Current Account ---
|
// --- Savings Account → Current Account ---
|
||||||
@@ -494,27 +504,33 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
|||||||
.orElseThrow(() -> new GeneralPlatformDomainRuleException(
|
.orElseThrow(() -> new GeneralPlatformDomainRuleException(
|
||||||
"error.msg.currentaccount.not.found", "Current account not found: " + accountTransferDTO.getToAccountId()));
|
"error.msg.currentaccount.not.found", "Current account not found: " + accountTransferDTO.getToAccountId()));
|
||||||
|
|
||||||
|
// skipAccountingPostings=true: current account deposit leg (C-txn) posts
|
||||||
|
// DR SAVING INDIVIDUAL / CR CURRENT ACCOUNT directly. Savings withdrawal GL entries
|
||||||
|
// would produce a self-cancelling DR+CR on the same SAVING INDIVIDUAL GL — suppress them.
|
||||||
final SavingsTransactionBooleanValues txnBooleans = new SavingsTransactionBooleanValues(isAccountTransfer,
|
final SavingsTransactionBooleanValues txnBooleans = new SavingsTransactionBooleanValues(isAccountTransfer,
|
||||||
isRegularTransaction, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), false,
|
isRegularTransaction, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), false,
|
||||||
accountTransferDTO.isExceptionForBalanceCheck());
|
accountTransferDTO.isExceptionForBalanceCheck(), true);
|
||||||
final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount,
|
final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount,
|
||||||
accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(),
|
accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(),
|
||||||
accountTransferDTO.getTransactionAmount(), accountTransferDTO.getPaymentDetail(),
|
accountTransferDTO.getTransactionAmount(), accountTransferDTO.getPaymentDetail(),
|
||||||
txnBooleans, backdatedTxnsAllowedTill);
|
txnBooleans, backdatedTxnsAllowedTill);
|
||||||
|
|
||||||
performCurrentDeposit(toCurrentAccount, accountTransferDTO.getTransactionAmount(),
|
performCurrentDeposit(toCurrentAccount, accountTransferDTO.getTransactionAmount(),
|
||||||
accountTransferDTO.getTransactionDate());
|
accountTransferDTO.getTransactionDate(),
|
||||||
|
fromSavingsAccount.productId(), fromSavingsAccount.getId());
|
||||||
|
|
||||||
final AccountTransferDetails newDetails = AccountTransferDetails.savingsToCurrentTransfer(
|
if (accountTransferDetails == null) {
|
||||||
fromSavingsAccount.office(), fromSavingsAccount.getClient(), fromSavingsAccount,
|
accountTransferDetails = AccountTransferDetails.savingsToCurrentTransfer(
|
||||||
toCurrentAccount.getOffice(), toCurrentAccount.getClient(), toCurrentAccount,
|
fromSavingsAccount.office(), fromSavingsAccount.getClient(), fromSavingsAccount,
|
||||||
accountTransferDTO.getTransferType());
|
toCurrentAccount.getOffice(), toCurrentAccount.getClient(), toCurrentAccount,
|
||||||
|
accountTransferDTO.getTransferType());
|
||||||
|
}
|
||||||
final Money amount = Money.of(fromSavingsAccount.getCurrency(), accountTransferDTO.getTransactionAmount());
|
final Money amount = Money.of(fromSavingsAccount.getCurrency(), accountTransferDTO.getTransactionAmount());
|
||||||
newDetails.addAccountTransferTransaction(AccountTransferTransaction.savingsToSavingsTransfer(
|
accountTransferDetails.addAccountTransferTransaction(AccountTransferTransaction.savingsToSavingsTransfer(
|
||||||
newDetails, withdrawal, null, accountTransferDTO.getTransactionDate(), amount,
|
accountTransferDetails, withdrawal, null, accountTransferDTO.getTransactionDate(), amount,
|
||||||
accountTransferDTO.getDescription()));
|
accountTransferDTO.getDescription()));
|
||||||
this.accountTransferDetailRepository.saveAndFlush(newDetails);
|
this.accountTransferDetailRepository.saveAndFlush(accountTransferDetails);
|
||||||
transferTransactionId = newDetails.getId();
|
transferTransactionId = accountTransferDetails.getId();
|
||||||
|
|
||||||
} else if (isCurrentToCurrentAccountTransfer(accountTransferDTO.getFromAccountType(), accountTransferDTO.getToAccountType())) {
|
} else if (isCurrentToCurrentAccountTransfer(accountTransferDTO.getFromAccountType(), accountTransferDTO.getToAccountType())) {
|
||||||
// --- Current Account → Current Account ---
|
// --- Current Account → Current Account ---
|
||||||
@@ -528,22 +544,26 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
|||||||
"error.msg.currentaccount.not.found", "Current account not found: " + accountTransferDTO.getToAccountId()));
|
"error.msg.currentaccount.not.found", "Current account not found: " + accountTransferDTO.getToAccountId()));
|
||||||
|
|
||||||
performCurrentWithdrawal(fromCurrentAccount, accountTransferDTO.getTransactionAmount(),
|
performCurrentWithdrawal(fromCurrentAccount, accountTransferDTO.getTransactionAmount(),
|
||||||
accountTransferDTO.getTransactionDate());
|
accountTransferDTO.getTransactionDate(),
|
||||||
|
toCurrentAccount.getProductId(), toCurrentAccount.getId());
|
||||||
performCurrentDeposit(toCurrentAccount, accountTransferDTO.getTransactionAmount(),
|
performCurrentDeposit(toCurrentAccount, accountTransferDTO.getTransactionAmount(),
|
||||||
accountTransferDTO.getTransactionDate());
|
accountTransferDTO.getTransactionDate(),
|
||||||
|
fromCurrentAccount.getProductId(), fromCurrentAccount.getId());
|
||||||
|
|
||||||
final AccountTransferDetails newDetails = AccountTransferDetails.currentToCurrentTransfer(
|
if (accountTransferDetails == null) {
|
||||||
fromCurrentAccount.getOffice(), fromCurrentAccount.getClient(), fromCurrentAccount,
|
accountTransferDetails = AccountTransferDetails.currentToCurrentTransfer(
|
||||||
toCurrentAccount.getOffice(), toCurrentAccount.getClient(), toCurrentAccount,
|
fromCurrentAccount.getOffice(), fromCurrentAccount.getClient(), fromCurrentAccount,
|
||||||
accountTransferDTO.getTransferType());
|
toCurrentAccount.getOffice(), toCurrentAccount.getClient(), toCurrentAccount,
|
||||||
|
accountTransferDTO.getTransferType());
|
||||||
|
}
|
||||||
final MonetaryCurrency currency = new MonetaryCurrency(fromCurrentAccount.getCurrencyCode(),
|
final MonetaryCurrency currency = new MonetaryCurrency(fromCurrentAccount.getCurrencyCode(),
|
||||||
fromCurrentAccount.getCurrencyDigits(), fromCurrentAccount.getCurrencyMultiplesOf());
|
fromCurrentAccount.getCurrencyDigits(), fromCurrentAccount.getCurrencyMultiplesOf());
|
||||||
final Money amount = Money.of(currency, accountTransferDTO.getTransactionAmount());
|
final Money amount = Money.of(currency, accountTransferDTO.getTransactionAmount());
|
||||||
newDetails.addAccountTransferTransaction(AccountTransferTransaction.savingsToSavingsTransfer(
|
accountTransferDetails.addAccountTransferTransaction(AccountTransferTransaction.savingsToSavingsTransfer(
|
||||||
newDetails, null, null, accountTransferDTO.getTransactionDate(), amount,
|
accountTransferDetails, null, null, accountTransferDTO.getTransactionDate(), amount,
|
||||||
accountTransferDTO.getDescription()));
|
accountTransferDTO.getDescription()));
|
||||||
this.accountTransferDetailRepository.saveAndFlush(newDetails);
|
this.accountTransferDetailRepository.saveAndFlush(accountTransferDetails);
|
||||||
transferTransactionId = newDetails.getId();
|
transferTransactionId = accountTransferDetails.getId();
|
||||||
|
|
||||||
} else if (isCurrentToLoanAccountTransfer(accountTransferDTO.getFromAccountType(), accountTransferDTO.getToAccountType())) {
|
} else if (isCurrentToLoanAccountTransfer(accountTransferDTO.getFromAccountType(), accountTransferDTO.getToAccountType())) {
|
||||||
// --- Current Account → Loan Account ---
|
// --- Current Account → Loan Account ---
|
||||||
@@ -553,7 +573,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
|||||||
"error.msg.currentaccount.not.found", "Current account not found: " + accountTransferDTO.getFromAccountId()));
|
"error.msg.currentaccount.not.found", "Current account not found: " + accountTransferDTO.getFromAccountId()));
|
||||||
final Loan toLoanAccount = this.loanAccountAssembler.assembleFrom(accountTransferDTO.getToAccountId());
|
final Loan toLoanAccount = this.loanAccountAssembler.assembleFrom(accountTransferDTO.getToAccountId());
|
||||||
|
|
||||||
performCurrentWithdrawal(fromCurrentAccount, accountTransferDTO.getTransactionAmount(),
|
performCurrentWithdrawalForLoan(fromCurrentAccount, accountTransferDTO.getTransactionAmount(),
|
||||||
accountTransferDTO.getTransactionDate());
|
accountTransferDTO.getTransactionDate());
|
||||||
|
|
||||||
ExternalId externalId = externalIdFactory.create(accountTransferDTO.getTxnExternalId().getValue());
|
ExternalId externalId = externalIdFactory.create(accountTransferDTO.getTxnExternalId().getValue());
|
||||||
@@ -656,10 +676,10 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Withdraw amount from a current account and save the transaction.
|
* Withdraw for Current → Loan transfers. Loan domain service handles the loan-side GL,
|
||||||
* Throws {@link GeneralPlatformDomainRuleException} if balance is insufficient.
|
* so current account side uses LIABILITY_TRANSFER as the counterpart (classic approach).
|
||||||
*/
|
*/
|
||||||
private CurrentAccountTransaction performCurrentWithdrawal(final CurrentAccount account, final BigDecimal amount,
|
private CurrentAccountTransaction performCurrentWithdrawalForLoan(final CurrentAccount account, final BigDecimal amount,
|
||||||
final LocalDate txnDate) {
|
final LocalDate txnDate) {
|
||||||
final BigDecimal balance = account.getAccountBalanceDerived() != null ? account.getAccountBalanceDerived() : BigDecimal.ZERO;
|
final BigDecimal balance = account.getAccountBalanceDerived() != null ? account.getAccountBalanceDerived() : BigDecimal.ZERO;
|
||||||
final BigDecimal onHold = account.getOnHoldFundsDerived() != null ? account.getOnHoldFundsDerived() : BigDecimal.ZERO;
|
final BigDecimal onHold = account.getOnHoldFundsDerived() != null ? account.getOnHoldFundsDerived() : BigDecimal.ZERO;
|
||||||
@@ -677,6 +697,40 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
|||||||
account.setTotalWithdrawalsDerived(
|
account.setTotalWithdrawalsDerived(
|
||||||
(account.getTotalWithdrawalsDerived() != null ? account.getTotalWithdrawalsDerived() : BigDecimal.ZERO).add(amount));
|
(account.getTotalWithdrawalsDerived() != null ? account.getTotalWithdrawalsDerived() : BigDecimal.ZERO).add(amount));
|
||||||
currentAccountRepository.save(account);
|
currentAccountRepository.save(account);
|
||||||
|
if (account.getProductId() != null && txn.getId() != null) {
|
||||||
|
final String currentTxnId = "CA" + txn.getId();
|
||||||
|
accountingProcessorHelper.createCashBasedJournalEntriesAndReversalsForSavings(account.getOffice(),
|
||||||
|
account.getCurrencyCode(), CashAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||||
|
FinancialActivity.LIABILITY_TRANSFER.getValue(), account.getProductId(), null,
|
||||||
|
account.getId(), currentTxnId, txnDate, amount, false);
|
||||||
|
}
|
||||||
|
return txn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Withdraw amount from a current account and save the transaction.
|
||||||
|
* Throws {@link GeneralPlatformDomainRuleException} if balance is insufficient.
|
||||||
|
*/
|
||||||
|
private CurrentAccountTransaction performCurrentWithdrawal(final CurrentAccount account, final BigDecimal amount,
|
||||||
|
final LocalDate txnDate, final Long counterpartProductId, final Long counterpartEntityId) {
|
||||||
|
final BigDecimal balance = account.getAccountBalanceDerived() != null ? account.getAccountBalanceDerived() : BigDecimal.ZERO;
|
||||||
|
final BigDecimal onHold = account.getOnHoldFundsDerived() != null ? account.getOnHoldFundsDerived() : BigDecimal.ZERO;
|
||||||
|
final BigDecimal available = balance.subtract(onHold);
|
||||||
|
if (!account.isAllowOverdraft() && amount.compareTo(available) > 0) {
|
||||||
|
throw new GeneralPlatformDomainRuleException("error.msg.current.account.insufficient.balance",
|
||||||
|
"Insufficient balance in current account " + account.getId()
|
||||||
|
+ ". Available: " + available + ", Requested: " + amount, account.getId());
|
||||||
|
}
|
||||||
|
final CurrentAccountTransaction txn = CurrentAccountTransaction.withdrawal(account, account.getOffice(), amount, txnDate, null);
|
||||||
|
final BigDecimal newBalance = balance.subtract(amount);
|
||||||
|
txn.setRunningBalanceDerived(newBalance);
|
||||||
|
currentAccountTransactionRepository.saveAndFlush(txn);
|
||||||
|
account.setAccountBalanceDerived(newBalance);
|
||||||
|
account.setTotalWithdrawalsDerived(
|
||||||
|
(account.getTotalWithdrawalsDerived() != null ? account.getTotalWithdrawalsDerived() : BigDecimal.ZERO).add(amount));
|
||||||
|
currentAccountRepository.save(account);
|
||||||
|
// Post journal entries: DR current account GL, CR counterpart GL — each with correct entity/account number
|
||||||
|
postCurrentAccountTransferJournalEntries(account, txn, amount, txnDate, true, counterpartProductId, counterpartEntityId);
|
||||||
return txn;
|
return txn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -684,7 +738,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
|||||||
* Deposit amount into a current account and save the transaction.
|
* Deposit amount into a current account and save the transaction.
|
||||||
*/
|
*/
|
||||||
private CurrentAccountTransaction performCurrentDeposit(final CurrentAccount account, final BigDecimal amount,
|
private CurrentAccountTransaction performCurrentDeposit(final CurrentAccount account, final BigDecimal amount,
|
||||||
final LocalDate txnDate) {
|
final LocalDate txnDate, final Long counterpartProductId, final Long counterpartEntityId) {
|
||||||
final BigDecimal balance = account.getAccountBalanceDerived() != null ? account.getAccountBalanceDerived() : BigDecimal.ZERO;
|
final BigDecimal balance = account.getAccountBalanceDerived() != null ? account.getAccountBalanceDerived() : BigDecimal.ZERO;
|
||||||
final CurrentAccountTransaction txn = CurrentAccountTransaction.deposit(account, account.getOffice(), amount, txnDate, null);
|
final CurrentAccountTransaction txn = CurrentAccountTransaction.deposit(account, account.getOffice(), amount, txnDate, null);
|
||||||
final BigDecimal newBalance = balance.add(amount);
|
final BigDecimal newBalance = balance.add(amount);
|
||||||
@@ -694,9 +748,67 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
|||||||
account.setTotalDepositsDerived(
|
account.setTotalDepositsDerived(
|
||||||
(account.getTotalDepositsDerived() != null ? account.getTotalDepositsDerived() : BigDecimal.ZERO).add(amount));
|
(account.getTotalDepositsDerived() != null ? account.getTotalDepositsDerived() : BigDecimal.ZERO).add(amount));
|
||||||
currentAccountRepository.save(account);
|
currentAccountRepository.save(account);
|
||||||
|
// Post journal entries: DR counterpart GL, CR current account GL — each with correct entity/account number
|
||||||
|
postCurrentAccountTransferJournalEntries(account, txn, amount, txnDate, false, counterpartProductId, counterpartEntityId);
|
||||||
return txn;
|
return txn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Posts double-entry journal entries for a current account leg of an account transfer.
|
||||||
|
* <p>
|
||||||
|
* Current Product GL mappings are stored under {@code PortfolioProductType.SAVING}, so the
|
||||||
|
* savings JE helper resolves them correctly.
|
||||||
|
* <p>
|
||||||
|
* Transaction id is prefixed with "C" (e.g. {@code C57}) so the entries are NOT grouped with
|
||||||
|
* savings entries that share the same numeric id (those use prefix "S"). The helper only
|
||||||
|
* appends its own "S" prefix when the id is numeric; passing "C57" keeps it as-is.
|
||||||
|
*
|
||||||
|
* @param isWithdrawal {@code true} for the from-leg (DR control / CR liability transfer);
|
||||||
|
* {@code false} for the to-leg (DR liability transfer / CR control)
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Posts direct transfer journal entries between a current account and a counterpart savings/current account.
|
||||||
|
* Each entry carries the correct entity ID so the correct account number appears on each GL line.
|
||||||
|
*
|
||||||
|
* For withdrawal (current → savings):
|
||||||
|
* DR: current product GL (entity = current account)
|
||||||
|
* CR: counterpart product GL (entity = savings/current account)
|
||||||
|
*
|
||||||
|
* For deposit (savings → current):
|
||||||
|
* DR: counterpart product GL (entity = savings/current account)
|
||||||
|
* CR: current product GL (entity = current account)
|
||||||
|
*
|
||||||
|
* @param counterpartProductId savings/current product ID of the other account
|
||||||
|
* @param counterpartEntityId savings/current account ID of the other account
|
||||||
|
*/
|
||||||
|
private void postCurrentAccountTransferJournalEntries(final CurrentAccount account, final CurrentAccountTransaction txn,
|
||||||
|
final BigDecimal amount, final LocalDate txnDate, final boolean isWithdrawal,
|
||||||
|
final Long counterpartProductId, final Long counterpartEntityId) {
|
||||||
|
if (account.getProductId() == null || txn.getId() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Prefix "CA" so:
|
||||||
|
// 1. The helper does NOT re-prefix with "S" (avoids txn id collision with savings "S" prefix)
|
||||||
|
// 2. JournalEntryReadPlatformServiceImpl joins m_current_account (transaction_id LIKE 'CA%')
|
||||||
|
// so the correct current account number appears on the DR/CR entry.
|
||||||
|
final String currentTxnId = "CA" + txn.getId();
|
||||||
|
if (isWithdrawal) {
|
||||||
|
// DR: current account GL CR: counterpart (savings/current) GL
|
||||||
|
accountingProcessorHelper.createDirectTransferJournalEntriesForSavings(
|
||||||
|
account.getOffice(), account.getCurrencyCode(),
|
||||||
|
account.getProductId(), account.getId(),
|
||||||
|
counterpartProductId, counterpartEntityId,
|
||||||
|
currentTxnId, txnDate, amount);
|
||||||
|
} else {
|
||||||
|
// DR: counterpart (savings/current) GL CR: current account GL
|
||||||
|
accountingProcessorHelper.createDirectTransferJournalEntriesForSavings(
|
||||||
|
account.getOffice(), account.getCurrencyCode(),
|
||||||
|
counterpartProductId, counterpartEntityId,
|
||||||
|
account.getProductId(), account.getId(),
|
||||||
|
currentTxnId, txnDate, amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public CommandProcessingResult refundByTransfer(JsonCommand command) {
|
public CommandProcessingResult refundByTransfer(JsonCommand command) {
|
||||||
|
|||||||
+4
-2
@@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.account.starter;
|
package org.apache.fineract.portfolio.account.starter;
|
||||||
|
|
||||||
|
import org.apache.fineract.accounting.journalentry.service.AccountingProcessorHelper;
|
||||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||||
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
||||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||||
@@ -94,12 +95,13 @@ public class AccountConfiguration {
|
|||||||
AccountTransferDetailRepository accountTransferDetailRepository, LoanReadPlatformService loanReadPlatformService,
|
AccountTransferDetailRepository accountTransferDetailRepository, LoanReadPlatformService loanReadPlatformService,
|
||||||
GSIMRepositoy gsimRepository, ConfigurationDomainService configurationDomainService, ExternalIdFactory externalIdFactory,
|
GSIMRepositoy gsimRepository, ConfigurationDomainService configurationDomainService, ExternalIdFactory externalIdFactory,
|
||||||
FineractProperties fineractProperties, CurrentAccountRepository currentAccountRepository,
|
FineractProperties fineractProperties, CurrentAccountRepository currentAccountRepository,
|
||||||
CurrentAccountTransactionRepository currentAccountTransactionRepository) {
|
CurrentAccountTransactionRepository currentAccountTransactionRepository,
|
||||||
|
AccountingProcessorHelper accountingProcessorHelper) {
|
||||||
return new AccountTransfersWritePlatformServiceImpl(accountTransfersDataValidator, accountTransferAssembler,
|
return new AccountTransfersWritePlatformServiceImpl(accountTransfersDataValidator, accountTransferAssembler,
|
||||||
accountTransferRepository, savingsAccountAssembler, savingsAccountDomainService, loanAccountAssembler,
|
accountTransferRepository, savingsAccountAssembler, savingsAccountDomainService, loanAccountAssembler,
|
||||||
loanAccountDomainService, savingsAccountWritePlatformService, accountTransferDetailRepository, loanReadPlatformService,
|
loanAccountDomainService, savingsAccountWritePlatformService, accountTransferDetailRepository, loanReadPlatformService,
|
||||||
gsimRepository, configurationDomainService, externalIdFactory, fineractProperties,
|
gsimRepository, configurationDomainService, externalIdFactory, fineractProperties,
|
||||||
currentAccountRepository, currentAccountTransactionRepository);
|
currentAccountRepository, currentAccountTransactionRepository, accountingProcessorHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|||||||
+27
-4
@@ -139,8 +139,10 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
|||||||
}
|
}
|
||||||
this.savingsAccountRepository.save(account);
|
this.savingsAccountRepository.save(account);
|
||||||
|
|
||||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, transactionBooleanValues.isAccountTransfer(),
|
if (!transactionBooleanValues.isSkipAccountingPostings()) {
|
||||||
backdatedTxnsAllowedTill);
|
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds,
|
||||||
|
transactionBooleanValues.isAccountTransfer(), backdatedTxnsAllowedTill);
|
||||||
|
}
|
||||||
|
|
||||||
businessEventNotifierService.notifyPostBusinessEvent(new SavingsWithdrawalBusinessEvent(withdrawal));
|
businessEventNotifierService.notifyPostBusinessEvent(new SavingsWithdrawalBusinessEvent(withdrawal));
|
||||||
return withdrawal;
|
return withdrawal;
|
||||||
@@ -153,13 +155,32 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
|||||||
final boolean isAccountTransfer, final boolean isRegularTransaction, final boolean backdatedTxnsAllowedTill) {
|
final boolean isAccountTransfer, final boolean isRegularTransaction, final boolean backdatedTxnsAllowedTill) {
|
||||||
final SavingsAccountTransactionType savingsAccountTransactionType = SavingsAccountTransactionType.DEPOSIT;
|
final SavingsAccountTransactionType savingsAccountTransactionType = SavingsAccountTransactionType.DEPOSIT;
|
||||||
return handleDeposit(account, fmt, transactionDate, transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction,
|
return handleDeposit(account, fmt, transactionDate, transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction,
|
||||||
savingsAccountTransactionType, backdatedTxnsAllowedTill);
|
savingsAccountTransactionType, backdatedTxnsAllowedTill, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SavingsAccountTransaction handleDeposit(final SavingsAccount account, final DateTimeFormatter fmt,
|
||||||
|
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail,
|
||||||
|
final boolean isAccountTransfer, final boolean isRegularTransaction, final boolean backdatedTxnsAllowedTill,
|
||||||
|
final boolean skipAccountingPostings) {
|
||||||
|
final SavingsAccountTransactionType savingsAccountTransactionType = SavingsAccountTransactionType.DEPOSIT;
|
||||||
|
return handleDeposit(account, fmt, transactionDate, transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction,
|
||||||
|
savingsAccountTransactionType, backdatedTxnsAllowedTill, skipAccountingPostings);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SavingsAccountTransaction handleDeposit(final SavingsAccount account, final DateTimeFormatter fmt,
|
private SavingsAccountTransaction handleDeposit(final SavingsAccount account, final DateTimeFormatter fmt,
|
||||||
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail,
|
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail,
|
||||||
final boolean isAccountTransfer, final boolean isRegularTransaction,
|
final boolean isAccountTransfer, final boolean isRegularTransaction,
|
||||||
final SavingsAccountTransactionType savingsAccountTransactionType, final boolean backdatedTxnsAllowedTill) {
|
final SavingsAccountTransactionType savingsAccountTransactionType, final boolean backdatedTxnsAllowedTill) {
|
||||||
|
return handleDeposit(account, fmt, transactionDate, transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction,
|
||||||
|
savingsAccountTransactionType, backdatedTxnsAllowedTill, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SavingsAccountTransaction handleDeposit(final SavingsAccount account, final DateTimeFormatter fmt,
|
||||||
|
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail,
|
||||||
|
final boolean isAccountTransfer, final boolean isRegularTransaction,
|
||||||
|
final SavingsAccountTransactionType savingsAccountTransactionType, final boolean backdatedTxnsAllowedTill,
|
||||||
|
final boolean skipAccountingPostings) {
|
||||||
context.authenticatedUser();
|
context.authenticatedUser();
|
||||||
account.validateForAccountBlock();
|
account.validateForAccountBlock();
|
||||||
account.validateForCreditBlock();
|
account.validateForCreditBlock();
|
||||||
@@ -210,7 +231,9 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
|||||||
|
|
||||||
this.savingsAccountRepository.saveAndFlush(account);
|
this.savingsAccountRepository.saveAndFlush(account);
|
||||||
|
|
||||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, backdatedTxnsAllowedTill);
|
if (!skipAccountingPostings) {
|
||||||
|
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, backdatedTxnsAllowedTill);
|
||||||
|
}
|
||||||
businessEventNotifierService.notifyPostBusinessEvent(new SavingsDepositBusinessEvent(deposit));
|
businessEventNotifierService.notifyPostBusinessEvent(new SavingsDepositBusinessEvent(deposit));
|
||||||
return deposit;
|
return deposit;
|
||||||
}
|
}
|
||||||
|
|||||||
+11
@@ -25,15 +25,22 @@ public class SavingsTransactionBooleanValues {
|
|||||||
private final boolean isApplyWithdrawFee;
|
private final boolean isApplyWithdrawFee;
|
||||||
private final boolean isInterestTransfer;
|
private final boolean isInterestTransfer;
|
||||||
private final boolean isExceptionForBalanceCheck;
|
private final boolean isExceptionForBalanceCheck;
|
||||||
|
private final boolean skipAccountingPostings;
|
||||||
|
|
||||||
public SavingsTransactionBooleanValues(final boolean isAccountTransfer, final boolean isRegularTransaction,
|
public SavingsTransactionBooleanValues(final boolean isAccountTransfer, final boolean isRegularTransaction,
|
||||||
final boolean isApplyWithdrawFee, final boolean isInterestTransfer, final boolean isExceptionForBalanceCheck) {
|
final boolean isApplyWithdrawFee, final boolean isInterestTransfer, final boolean isExceptionForBalanceCheck) {
|
||||||
|
this(isAccountTransfer, isRegularTransaction, isApplyWithdrawFee, isInterestTransfer, isExceptionForBalanceCheck, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SavingsTransactionBooleanValues(final boolean isAccountTransfer, final boolean isRegularTransaction,
|
||||||
|
final boolean isApplyWithdrawFee, final boolean isInterestTransfer, final boolean isExceptionForBalanceCheck,
|
||||||
|
final boolean skipAccountingPostings) {
|
||||||
this.isAccountTransfer = isAccountTransfer;
|
this.isAccountTransfer = isAccountTransfer;
|
||||||
this.isRegularTransaction = isRegularTransaction;
|
this.isRegularTransaction = isRegularTransaction;
|
||||||
this.isApplyWithdrawFee = isApplyWithdrawFee;
|
this.isApplyWithdrawFee = isApplyWithdrawFee;
|
||||||
this.isInterestTransfer = isInterestTransfer;
|
this.isInterestTransfer = isInterestTransfer;
|
||||||
this.isExceptionForBalanceCheck = isExceptionForBalanceCheck;
|
this.isExceptionForBalanceCheck = isExceptionForBalanceCheck;
|
||||||
|
this.skipAccountingPostings = skipAccountingPostings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAccountTransfer() {
|
public boolean isAccountTransfer() {
|
||||||
@@ -56,4 +63,8 @@ public class SavingsTransactionBooleanValues {
|
|||||||
return this.isExceptionForBalanceCheck;
|
return this.isExceptionForBalanceCheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSkipAccountingPostings() {
|
||||||
|
return this.skipAccountingPostings;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -38,6 +38,10 @@ public interface SavingsAccountDomainService {
|
|||||||
BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean isAccountTransfer, boolean isRegularTransaction,
|
BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean isAccountTransfer, boolean isRegularTransaction,
|
||||||
boolean backdatedTxnsAllowedTill);
|
boolean backdatedTxnsAllowedTill);
|
||||||
|
|
||||||
|
SavingsAccountTransaction handleDeposit(SavingsAccount account, DateTimeFormatter fmt, LocalDate transactionDate,
|
||||||
|
BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean isAccountTransfer, boolean isRegularTransaction,
|
||||||
|
boolean backdatedTxnsAllowedTill, boolean skipAccountingPostings);
|
||||||
|
|
||||||
void postJournalEntries(SavingsAccount savingsAccount, Set<Long> existingTransactionIds, Set<Long> existingReversedTransactionIds,
|
void postJournalEntries(SavingsAccount savingsAccount, Set<Long> existingTransactionIds, Set<Long> existingReversedTransactionIds,
|
||||||
boolean backdatedTxnsAllowedTill);
|
boolean backdatedTxnsAllowedTill);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user