feat: FD/RD GL transaction prefixes + savingsAccountNo in journal entry API
- Use FD/RD transaction ID prefixes for Fixed/Recurring Deposit GL entries via ThreadLocal context set in Cash/AccrualBasedAccountingProcessorForSavings - Add depositAccountType to SavingsDTO and pass from SavingsAccount bridge data - Add savingsAccountNo field to JournalEntryData; populate via LEFT JOIN on m_savings_account (SB/FD/RD) and m_current_account (CA prefix) in read query - Fix JournalEntryMapper MapStruct: ignore savingsAccountNo (SQL-populated) - Fix JournalEntryRunningBalanceUpdateServiceImpl constructor call (27 params) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
be26ba16c9
commit
b25d5a30d2
+1
@@ -73,6 +73,7 @@ public interface JournalEntryMapper {
|
|||||||
@Mapping(target = "transactionDetails", ignore = true)
|
@Mapping(target = "transactionDetails", ignore = true)
|
||||||
@Mapping(target = "savingTransactionId", ignore = true)
|
@Mapping(target = "savingTransactionId", ignore = true)
|
||||||
@Mapping(target = "externalAssetOwner", ignore = true)
|
@Mapping(target = "externalAssetOwner", ignore = true)
|
||||||
|
@Mapping(target = "savingsAccountNo", ignore = true)
|
||||||
JournalEntryData map(JournalEntry journalEntry);
|
JournalEntryData map(JournalEntry journalEntry);
|
||||||
|
|
||||||
@Named("entityType")
|
@Named("entityType")
|
||||||
|
|||||||
+6
-2
@@ -59,6 +59,8 @@ public class JournalEntryData {
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private Long entityId;
|
private Long entityId;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
private String savingsAccountNo;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private Long createdByUserId;
|
private Long createdByUserId;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private OffsetDateTime createdDate;
|
private OffsetDateTime createdDate;
|
||||||
@@ -193,7 +195,8 @@ public class JournalEntryData {
|
|||||||
final EnumOptionData entityType, final Long entityId, final Long createdByUserId, final OffsetDateTime submittedOnDate,
|
final EnumOptionData entityType, final Long entityId, final Long createdByUserId, final OffsetDateTime submittedOnDate,
|
||||||
final String createdByUserName, final String comments, final Boolean reversed, final String referenceNumber,
|
final String createdByUserName, final String comments, final Boolean reversed, final String referenceNumber,
|
||||||
final BigDecimal officeRunningBalance, final BigDecimal organizationRunningBalance, final Boolean runningBalanceComputed,
|
final BigDecimal officeRunningBalance, final BigDecimal organizationRunningBalance, final Boolean runningBalanceComputed,
|
||||||
final TransactionDetailData transactionDetailData, final CurrencyData currency, final String externalAssetOwner) {
|
final TransactionDetailData transactionDetailData, final CurrencyData currency, final String externalAssetOwner,
|
||||||
|
final String savingsAccountNo) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.officeId = officeId;
|
this.officeId = officeId;
|
||||||
this.officeName = officeName;
|
this.officeName = officeName;
|
||||||
@@ -221,6 +224,7 @@ public class JournalEntryData {
|
|||||||
this.transactionDetails = transactionDetailData;
|
this.transactionDetails = transactionDetailData;
|
||||||
this.currency = currency;
|
this.currency = currency;
|
||||||
this.externalAssetOwner = externalAssetOwner;
|
this.externalAssetOwner = externalAssetOwner;
|
||||||
|
this.savingsAccountNo = savingsAccountNo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JournalEntryData importInstance(Long officeId, LocalDate transactionDate, String currencyCode, Long paymentTypeId,
|
public static JournalEntryData importInstance(Long officeId, LocalDate transactionDate, String currencyCode, Long paymentTypeId,
|
||||||
@@ -266,7 +270,7 @@ public class JournalEntryData {
|
|||||||
return new JournalEntryData(id, officeId, officeName, glAccountName, glAccountId, glAccountCode, glAccountClassification,
|
return new JournalEntryData(id, officeId, officeName, glAccountName, glAccountId, glAccountCode, glAccountClassification,
|
||||||
transactionDate, entryType, amount, transactionId, manualEntry, entityType, entityId, createdByUserId, submittedOnDate,
|
transactionDate, entryType, amount, transactionId, manualEntry, entityType, entityId, createdByUserId, submittedOnDate,
|
||||||
createdByUserName, comments, reversed, referenceNumber, officeRunningBalance, organizationRunningBalance,
|
createdByUserName, comments, reversed, referenceNumber, officeRunningBalance, organizationRunningBalance,
|
||||||
runningBalanceComputed, transactionDetailData, currency, externalAssetOwner);
|
runningBalanceComputed, transactionDetailData, currency, externalAssetOwner, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getRowIndex() {
|
public Integer getRowIndex() {
|
||||||
|
|||||||
+1
@@ -35,4 +35,5 @@ public class SavingsDTO {
|
|||||||
private boolean cashBasedAccountingEnabled;
|
private boolean cashBasedAccountingEnabled;
|
||||||
private boolean accrualBasedAccountingEnabled;
|
private boolean accrualBasedAccountingEnabled;
|
||||||
private List<SavingsTransactionDTO> newSavingsTransactions;
|
private List<SavingsTransactionDTO> newSavingsTransactions;
|
||||||
|
private int depositAccountType;
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-3
@@ -83,10 +83,30 @@ public class AccountingProcessorHelper {
|
|||||||
|
|
||||||
public static final String LOAN_TRANSACTION_IDENTIFIER = "L";
|
public static final String LOAN_TRANSACTION_IDENTIFIER = "L";
|
||||||
public static final String SAVINGS_TRANSACTION_IDENTIFIER = "S";
|
public static final String SAVINGS_TRANSACTION_IDENTIFIER = "S";
|
||||||
|
public static final String FIXED_DEPOSIT_TRANSACTION_IDENTIFIER = "FD";
|
||||||
|
public static final String RECURRING_DEPOSIT_TRANSACTION_IDENTIFIER = "RD";
|
||||||
public static final String CLIENT_TRANSACTION_IDENTIFIER = "C";
|
public static final String CLIENT_TRANSACTION_IDENTIFIER = "C";
|
||||||
public static final String PROVISIONING_TRANSACTION_IDENTIFIER = "P";
|
public static final String PROVISIONING_TRANSACTION_IDENTIFIER = "P";
|
||||||
public static final String SHARE_TRANSACTION_IDENTIFIER = "SH";
|
public static final String SHARE_TRANSACTION_IDENTIFIER = "SH";
|
||||||
|
|
||||||
|
private static final ThreadLocal<Integer> DEPOSIT_ACCOUNT_TYPE_CONTEXT = ThreadLocal.withInitial(() -> 100);
|
||||||
|
|
||||||
|
public static void setDepositAccountTypeContext(int depositAccountType) {
|
||||||
|
DEPOSIT_ACCOUNT_TYPE_CONTEXT.set(depositAccountType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearDepositAccountTypeContext() {
|
||||||
|
DEPOSIT_ACCOUNT_TYPE_CONTEXT.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSavingsTransactionIdentifier() {
|
||||||
|
return switch (DEPOSIT_ACCOUNT_TYPE_CONTEXT.get()) {
|
||||||
|
case 200 -> FIXED_DEPOSIT_TRANSACTION_IDENTIFIER;
|
||||||
|
case 300 -> RECURRING_DEPOSIT_TRANSACTION_IDENTIFIER;
|
||||||
|
default -> SAVINGS_TRANSACTION_IDENTIFIER;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private final JournalEntryRepository glJournalEntryRepository;
|
private final JournalEntryRepository glJournalEntryRepository;
|
||||||
private final ProductToGLAccountMappingRepository accountMappingRepository;
|
private final ProductToGLAccountMappingRepository accountMappingRepository;
|
||||||
private final FinancialActivityAccountRepositoryWrapper financialActivityAccountRepository;
|
private final FinancialActivityAccountRepositoryWrapper financialActivityAccountRepository;
|
||||||
@@ -203,6 +223,9 @@ public class AccountingProcessorHelper {
|
|||||||
final Long loanProductId = (Long) accountingBridgeData.get("savingsProductId");
|
final Long loanProductId = (Long) accountingBridgeData.get("savingsProductId");
|
||||||
final Long officeId = (Long) accountingBridgeData.get("officeId");
|
final Long officeId = (Long) accountingBridgeData.get("officeId");
|
||||||
final String currencyCode = (String) accountingBridgeData.get("currencyCode");
|
final String currencyCode = (String) accountingBridgeData.get("currencyCode");
|
||||||
|
final int depositAccountType = accountingBridgeData.containsKey("depositAccountType")
|
||||||
|
? (Integer) accountingBridgeData.get("depositAccountType")
|
||||||
|
: 100;
|
||||||
final List<SavingsTransactionDTO> newSavingsTransactions = new ArrayList<>();
|
final List<SavingsTransactionDTO> newSavingsTransactions = new ArrayList<>();
|
||||||
boolean isAccountTransfer = (Boolean) accountingBridgeData.get("isAccountTransfer");
|
boolean isAccountTransfer = (Boolean) accountingBridgeData.get("isAccountTransfer");
|
||||||
|
|
||||||
@@ -264,7 +287,7 @@ public class AccountingProcessorHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new SavingsDTO(loanId, loanProductId, officeId, currencyCode, cashBasedAccountingEnabled, accrualBasedAccountingEnabled,
|
return new SavingsDTO(loanId, loanProductId, officeId, currencyCode, cashBasedAccountingEnabled, accrualBasedAccountingEnabled,
|
||||||
newSavingsTransactions);
|
newSavingsTransactions, depositAccountType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SharesDTO populateSharesDtoFromMap(final Map<String, Object> accountingBridgeData, final boolean cashBasedAccountingEnabled,
|
public SharesDTO populateSharesDtoFromMap(final Map<String, Object> accountingBridgeData, final boolean cashBasedAccountingEnabled,
|
||||||
@@ -898,7 +921,7 @@ public class AccountingProcessorHelper {
|
|||||||
String modifiedTransactionId = transactionId;
|
String modifiedTransactionId = transactionId;
|
||||||
if (StringUtils.isNumeric(transactionId)) {
|
if (StringUtils.isNumeric(transactionId)) {
|
||||||
savingsAccountTransactionId = Long.parseLong(transactionId);
|
savingsAccountTransactionId = Long.parseLong(transactionId);
|
||||||
modifiedTransactionId = SAVINGS_TRANSACTION_IDENTIFIER + transactionId;
|
modifiedTransactionId = getSavingsTransactionIdentifier() + transactionId;
|
||||||
}
|
}
|
||||||
final JournalEntry journalEntry = JournalEntry.createNew(office, null, account, currencyCode, modifiedTransactionId, manualEntry,
|
final JournalEntry journalEntry = JournalEntry.createNew(office, null, account, currencyCode, modifiedTransactionId, manualEntry,
|
||||||
transactionDate, JournalEntryType.CREDIT, amount, null, PortfolioProductType.SAVING.getValue(), savingsId, null, null,
|
transactionDate, JournalEntryType.CREDIT, amount, null, PortfolioProductType.SAVING.getValue(), savingsId, null, null,
|
||||||
@@ -964,7 +987,7 @@ public class AccountingProcessorHelper {
|
|||||||
String modifiedTransactionId = transactionId;
|
String modifiedTransactionId = transactionId;
|
||||||
if (StringUtils.isNumeric(transactionId)) {
|
if (StringUtils.isNumeric(transactionId)) {
|
||||||
savingsAccountTransactionId = Long.parseLong(transactionId);
|
savingsAccountTransactionId = Long.parseLong(transactionId);
|
||||||
modifiedTransactionId = SAVINGS_TRANSACTION_IDENTIFIER + transactionId;
|
modifiedTransactionId = getSavingsTransactionIdentifier() + transactionId;
|
||||||
}
|
}
|
||||||
final JournalEntry journalEntry = JournalEntry.createNew(office, null, account, currencyCode, modifiedTransactionId, manualEntry,
|
final JournalEntry journalEntry = JournalEntry.createNew(office, null, account, currencyCode, modifiedTransactionId, manualEntry,
|
||||||
transactionDate, JournalEntryType.DEBIT, amount, null, PortfolioProductType.SAVING.getValue(), savingsId, null, null,
|
transactionDate, JournalEntryType.DEBIT, amount, null, PortfolioProductType.SAVING.getValue(), savingsId, null, null,
|
||||||
|
|||||||
+5
@@ -40,6 +40,8 @@ public class AccrualBasedAccountingProcessorForSavings implements AccountingProc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createJournalEntriesForSavings(final SavingsDTO savingsDTO) {
|
public void createJournalEntriesForSavings(final SavingsDTO savingsDTO) {
|
||||||
|
AccountingProcessorHelper.setDepositAccountTypeContext(savingsDTO.getDepositAccountType());
|
||||||
|
try {
|
||||||
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(savingsDTO.getOfficeId());
|
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(savingsDTO.getOfficeId());
|
||||||
final Long savingsProductId = savingsDTO.getSavingsProductId();
|
final Long savingsProductId = savingsDTO.getSavingsProductId();
|
||||||
final Long savingsId = savingsDTO.getSavingsId();
|
final Long savingsId = savingsDTO.getSavingsId();
|
||||||
@@ -281,5 +283,8 @@ public class AccrualBasedAccountingProcessorForSavings implements AccountingProc
|
|||||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, feePayments);
|
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, feePayments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
AccountingProcessorHelper.clearDepositAccountTypeContext();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -39,6 +39,8 @@ public class CashBasedAccountingProcessorForSavings implements AccountingProcess
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createJournalEntriesForSavings(final SavingsDTO savingsDTO) {
|
public void createJournalEntriesForSavings(final SavingsDTO savingsDTO) {
|
||||||
|
AccountingProcessorHelper.setDepositAccountTypeContext(savingsDTO.getDepositAccountType());
|
||||||
|
try {
|
||||||
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(savingsDTO.getOfficeId());
|
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(savingsDTO.getOfficeId());
|
||||||
final Long savingsProductId = savingsDTO.getSavingsProductId();
|
final Long savingsProductId = savingsDTO.getSavingsProductId();
|
||||||
final Long savingsId = savingsDTO.getSavingsId();
|
final Long savingsId = savingsDTO.getSavingsId();
|
||||||
@@ -251,5 +253,8 @@ public class CashBasedAccountingProcessorForSavings implements AccountingProcess
|
|||||||
savingsId, transactionId, transactionDate, amount, isReversal, feePayments);
|
savingsId, transactionId, transactionDate, amount, isReversal, feePayments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
AccountingProcessorHelper.clearDepositAccountTypeContext();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-3
@@ -104,7 +104,12 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
|
|||||||
.append(" journalEntry.created_on_utc as submittedOnDate, journalEntry.reversed as reversed, ")
|
.append(" journalEntry.created_on_utc as submittedOnDate, journalEntry.reversed as reversed, ")
|
||||||
.append(" journalEntry.currency_code as currencyCode, curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, ")
|
.append(" journalEntry.currency_code as currencyCode, curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, ")
|
||||||
.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(" WHEN journalEntry.entity_type_enum = 2 AND journalEntry.transaction_id LIKE 'CA%' THEN ca.account_no ")
|
||||||
|
.append(" WHEN journalEntry.entity_type_enum = 2 THEN sa.account_no ")
|
||||||
|
.append(" ELSE NULL ")
|
||||||
|
.append(" END as savingsAccountNo ");
|
||||||
if (associationParametersData.isRunningBalanceRequired()) {
|
if (associationParametersData.isRunningBalanceRequired()) {
|
||||||
sb.append(" ,journalEntry.is_running_balance_calculated as runningBalanceComputed, ")
|
sb.append(" ,journalEntry.is_running_balance_calculated as runningBalanceComputed, ")
|
||||||
.append(" journalEntry.office_running_balance as officeRunningBalance, ")
|
.append(" journalEntry.office_running_balance as officeRunningBalance, ")
|
||||||
@@ -124,7 +129,9 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
|
|||||||
.append(" left join m_appuser as creatingUser on creatingUser.id = journalEntry.created_by ")
|
.append(" left join m_appuser as creatingUser on creatingUser.id = journalEntry.created_by ")
|
||||||
.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_current_account ca on ca.id = journalEntry.entity_id AND journalEntry.entity_type_enum = 2 AND journalEntry.transaction_id LIKE 'CA%' ");
|
||||||
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 ")
|
||||||
@@ -235,11 +242,12 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
|
|||||||
transactionDetailData = new TransactionDetailData(transaction, paymentDetailData, noteData, transactionTypeEnumData);
|
transactionDetailData = new TransactionDetailData(transaction, paymentDetailData, noteData, transactionTypeEnumData);
|
||||||
}
|
}
|
||||||
final String externalAssetOwner = rs.getString("externalAssetOwner");
|
final String externalAssetOwner = rs.getString("externalAssetOwner");
|
||||||
|
final String savingsAccountNo = rs.getString("savingsAccountNo");
|
||||||
|
|
||||||
return new JournalEntryData(id, officeId, officeName, glAccountName, glAccountId, glCode, accountType, transactionDate,
|
return new JournalEntryData(id, officeId, officeName, glAccountName, glAccountId, glCode, accountType, transactionDate,
|
||||||
entryType, amount, transactionId, manualEntry, entityType, entityId, createdByUserId, submittedOnDate,
|
entryType, amount, transactionId, manualEntry, entityType, entityId, createdByUserId, submittedOnDate,
|
||||||
createdByUserName, comments, reversed, referenceNumber, officeRunningBalance, organizationRunningBalance,
|
createdByUserName, comments, reversed, referenceNumber, officeRunningBalance, organizationRunningBalance,
|
||||||
runningBalanceComputed, transactionDetailData, currency, externalAssetOwner);
|
runningBalanceComputed, transactionDetailData, currency, externalAssetOwner, savingsAccountNo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -278,7 +278,7 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry
|
|||||||
final EnumOptionData entryType = AccountingEnumerations.journalEntryType(entryTypeId);
|
final EnumOptionData entryType = AccountingEnumerations.journalEntryType(entryTypeId);
|
||||||
|
|
||||||
return new JournalEntryData(id, officeId, null, null, glAccountId, null, accountType, null, entryType, amount, null, null, null,
|
return new JournalEntryData(id, officeId, null, null, glAccountId, null, accountType, null, entryType, amount, null, null, null,
|
||||||
null, null, null, null, null, null, null, null, null, null, null, null, null);
|
null, null, null, null, null, null, null, null, null, null, null, null, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -1894,6 +1894,7 @@ public class SavingsAccount extends AbstractAuditableWithUTCDateTimeCustom<Long>
|
|||||||
accountingBridgeData.put("cashBasedAccountingEnabled", isCashBasedAccountingEnabledOnSavingsProduct());
|
accountingBridgeData.put("cashBasedAccountingEnabled", isCashBasedAccountingEnabledOnSavingsProduct());
|
||||||
accountingBridgeData.put("accrualBasedAccountingEnabled", isAccrualBasedAccountingEnabledOnSavingsProduct());
|
accountingBridgeData.put("accrualBasedAccountingEnabled", isAccrualBasedAccountingEnabledOnSavingsProduct());
|
||||||
accountingBridgeData.put("isAccountTransfer", isAccountTransfer);
|
accountingBridgeData.put("isAccountTransfer", isAccountTransfer);
|
||||||
|
accountingBridgeData.put("depositAccountType", depositAccountType().getValue());
|
||||||
|
|
||||||
final List<Map<String, Object>> newSavingsTransactions = new ArrayList<>();
|
final List<Map<String, Object>> newSavingsTransactions = new ArrayList<>();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user