diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/domain/JournalEntry.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/domain/JournalEntry.java index b207954ad..b54f7d23f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/domain/JournalEntry.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/domain/JournalEntry.java @@ -28,7 +28,8 @@ import javax.persistence.ManyToOne; import javax.persistence.Table; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.accounting.glaccount.domain.GLAccount; -import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom; +import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom; +import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.organisation.office.domain.Office; import org.apache.fineract.portfolio.client.domain.ClientTransaction; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; @@ -37,7 +38,7 @@ import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction; @Entity @Table(name = "acc_gl_journal_entry") -public class JournalEntry extends AbstractAuditableCustom { +public class JournalEntry extends AbstractAuditableWithUTCDateTimeCustom { @ManyToOne @JoinColumn(name = "office_id", nullable = false) @@ -103,6 +104,9 @@ public class JournalEntry extends AbstractAuditableCustom { @Column(name = "ref_num") private String referenceNumber; + @Column(name = "submitted_on_date", nullable = false) + private LocalDate submittedOnDate; + public static JournalEntry createNew(final Office office, final PaymentDetail paymentDetail, final GLAccount glAccount, final String currencyCode, final String transactionId, final boolean manualEntry, final LocalDate transactionDate, final JournalEntryType journalEntryType, final BigDecimal amount, final String description, final Integer entityType, @@ -141,6 +145,7 @@ public class JournalEntry extends AbstractAuditableCustom { this.clientTransaction = clientTransaction; this.paymentDetail = paymentDetail; this.shareTransactionId = shareTransactionId; + this.submittedOnDate = DateUtils.getBusinessLocalDate(); } public boolean isDebitEntry() { @@ -227,4 +232,8 @@ public class JournalEntry extends AbstractAuditableCustom { return this.description; } + public LocalDate getSubmittedOnDate() { + return this.submittedOnDate; + } + } diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalEntryReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalEntryReadPlatformServiceImpl.java index d21c14b5e..907286de7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalEntryReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalEntryReadPlatformServiceImpl.java @@ -101,7 +101,7 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat .append(" journalEntry.type_enum as entryType,journalEntry.amount as amount, journalEntry.transaction_id as transactionId,") .append(" journalEntry.entity_type_enum as entityType, journalEntry.entity_id as entityId, creatingUser.id as createdByUserId, ") .append(" creatingUser.username as createdByUserName, journalEntry.description as comments, ") - .append(" journalEntry.created_date as createdDate, journalEntry.reversed as reversed, ") + .append(" journalEntry.submitted_on_date as createdDate, journalEntry.reversed as reversed, ") .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 "); if (associationParametersData.isRunningBalanceRequired()) { @@ -120,7 +120,7 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat sb.append(" from acc_gl_journal_entry as journalEntry ") .append(" left join acc_gl_account as glAccount on glAccount.id = journalEntry.account_id") .append(" left join m_office as office on office.id = journalEntry.office_id") - .append(" left join m_appuser as creatingUser on creatingUser.id = journalEntry.createdby_id ") + .append(" left join m_appuser as creatingUser on creatingUser.id = journalEntry.created_by ") .append(" join m_currency curr on curr.code = journalEntry.currency_code "); if (associationParametersData.isTransactionDetailsRequired()) { sb.append(" left join m_loan_transaction as lt on journalEntry.loan_transaction_id = lt.id ") diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalEntryRunningBalanceUpdateServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalEntryRunningBalanceUpdateServiceImpl.java index 42ea871a7..9a711e0f2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalEntryRunningBalanceUpdateServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalEntryRunningBalanceUpdateServiceImpl.java @@ -40,7 +40,9 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuild import org.apache.fineract.infrastructure.core.data.EnumOptionData; import org.apache.fineract.infrastructure.core.domain.JdbcSupport; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; +import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; @@ -63,6 +65,8 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry private final GLJournalEntryMapper entryMapper = new GLJournalEntryMapper(); + private final PlatformSecurityContext platformSecurityContext; + @Override public void updateRunningBalance() { String dateFinder = "select MIN(je.entry_date) as entityDate from acc_gl_journal_entry je " @@ -154,8 +158,10 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry if (entryDatas.size() > 0) { // run a batch update of 1000 SQL statements at a time final Integer batchUpdateSize = 1000; - ArrayList updateSql = new ArrayList<>(); + List params = new ArrayList<>(); int batchIndex = 0; + String sql = "UPDATE acc_gl_journal_entry SET is_running_balance_calculated=?, organization_running_balance=?," + + "office_running_balance=?, last_modified_by=?, last_modified_on_utc=? WHERE id=?"; for (int index = 0; index < entryDatas.size(); index++) { JournalEntryData entryData = entryDatas.get(index); Map officeRunningBalanceMap = null; @@ -167,18 +173,15 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry } BigDecimal officeRunningBalance = calculateRunningBalance(entryData, officeRunningBalanceMap); BigDecimal runningBalance = calculateRunningBalance(entryData, runningBalanceMap); - String sql = "UPDATE acc_gl_journal_entry SET is_running_balance_calculated=true, organization_running_balance=" - + runningBalance + ",office_running_balance=" + officeRunningBalance + " WHERE id=" + entryData.getId(); - updateSql.add(sql); + + params.add(new Object[] { Boolean.TRUE, runningBalance, officeRunningBalance, + platformSecurityContext.authenticatedUser().getId(), DateUtils.getOffsetDateTimeOfTenant(), entryData.getId() }); batchIndex++; if (batchIndex == batchUpdateSize || index == entryDatas.size() - 1) { - // run a batch update of the 1000 update SQL statements - String[] batch = new String[updateSql.size()]; - updateSql.toArray(batch); - this.jdbcTemplate.batchUpdate(batch); + this.jdbcTemplate.batchUpdate(sql, params); // reset counter and string array batchIndex = 0; - updateSql.clear(); + params.clear(); } } } @@ -202,14 +205,15 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry } } List entryDatas = jdbcTemplate.query(entryMapper.officeRunningBalanceSchema(), entryMapper, officeId, entityDate); - String[] updateSql = new String[entryDatas.size()]; - int i = 0; + List params = new ArrayList<>(); + + String sql = "UPDATE acc_gl_journal_entry SET office_running_balance=?, last_modified_by=?, last_modified_on_utc=? WHERE id=?"; for (JournalEntryData entryData : entryDatas) { BigDecimal runningBalance = calculateRunningBalance(entryData, runningBalanceMap); - String sql = "UPDATE acc_gl_journal_entry SET office_running_balance=" + runningBalance + " WHERE id=" + entryData.getId(); - updateSql[i++] = sql; + params.add(new Object[] { runningBalance, platformSecurityContext.authenticatedUser().getId(), + DateUtils.getOffsetDateTimeOfTenant(), entryData.getId() }); } - this.jdbcTemplate.batchUpdate(updateSql); + this.jdbcTemplate.batchUpdate(sql, params); } private BigDecimal calculateRunningBalance(JournalEntryData entry, Map runningBalanceMap) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/jobs/postinterestforsavings/PostInterestForSavingTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/jobs/postinterestforsavings/PostInterestForSavingTasklet.java index 2fd5839b9..020e109fa 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/jobs/postinterestforsavings/PostInterestForSavingTasklet.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/jobs/postinterestforsavings/PostInterestForSavingTasklet.java @@ -36,6 +36,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.infrastructure.core.domain.FineractContext; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.savings.data.SavingsAccountData; import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler; import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrapper; @@ -66,6 +67,7 @@ public class PostInterestForSavingTasklet implements Tasklet { private final Queue> queue = new ArrayDeque<>(); private final ApplicationContext applicationContext; private final int queueSize = 1; + private final PlatformSecurityContext securityContext; @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { @@ -157,6 +159,7 @@ public class PostInterestForSavingTasklet implements Tasklet { savingsSchedularInterestPoster.setBackdatedTxnsAllowedTill(backdatedTxnsAllowedTill); savingsSchedularInterestPoster.setTransactionTemplate(transactionTemplate); savingsSchedularInterestPoster.setConfigurationDomainService(configurationDomainService); + savingsSchedularInterestPoster.setPlatformSecurityContext(securityContext); posters.add(savingsSchedularInterestPoster); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularInterestPoster.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularInterestPoster.java index 729479168..2a1b92391 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularInterestPoster.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsSchedularInterestPoster.java @@ -39,6 +39,7 @@ import org.apache.fineract.infrastructure.core.domain.FineractContext; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.savings.data.SavingsAccountData; import org.apache.fineract.portfolio.savings.data.SavingsAccountSummaryData; import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData; @@ -82,6 +83,7 @@ public class SavingsSchedularInterestPoster implements Callable { private CommandStrategyProvider strategyProvider; private ResolutionHelper resolutionHelper; private SavingsAccountReadPlatformService savingsAccountReadPlatformService; + private PlatformSecurityContext platformSecurityContext; @Override @SuppressFBWarnings(value = { @@ -172,6 +174,7 @@ public class SavingsSchedularInterestPoster implements Callable { private void batchUpdateJournalEntries(final List savingsAccountDataList, final HashMap savingsAccountTransactionDataHashMap) throws DataAccessException, NullPointerException { + Long userId = platformSecurityContext.authenticatedUser().getId(); String queryForJGLUpdate = batchQueryForJournalEntries(); List paramsForGLInsertion = new ArrayList<>(); for (SavingsAccountData savingsAccountData : savingsAccountDataList) { @@ -182,7 +185,6 @@ public class SavingsSchedularInterestPoster implements Callable { if (savingsAccountTransactionData.getId() == null) { final String key = savingsAccountTransactionData.getRefNo(); if (savingsAccountTransactionDataHashMap.containsKey(key)) { - LocalDate currentDate = DateUtils.getLocalDateOfTenant(); final SavingsAccountTransactionData dataFromFetch = savingsAccountTransactionDataHashMap.get(key); savingsAccountTransactionData.setId(dataFromFetch.getId()); if (savingsAccountData.getGlAccountIdForSavingsControl() != 0 @@ -191,31 +193,23 @@ public class SavingsSchedularInterestPoster implements Callable { savingsAccountData.getOfficeId(), null, currencyCode, SAVINGS_TRANSACTION_IDENTIFIER + savingsAccountTransactionData.getId().toString(), savingsAccountTransactionData.getId(), null, false, null, false, - Date.from(savingsAccountTransactionData.getTransactionDate() - .atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant()), - JournalEntryType.CREDIT.getValue().longValue(), savingsAccountTransactionData.getAmount(), null, - JournalEntryType.CREDIT.getValue().longValue(), savingsAccountData.getId(), - Date.from(currentDate.atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant()), - Date.from(currentDate.atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant()), false, - BigDecimal.ZERO, BigDecimal.ZERO, null, - Date.from(savingsAccountTransactionData.getTransactionDate() - .atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant()), - null, Integer.valueOf(1), Integer.valueOf(1) }); + savingsAccountTransactionData.getTransactionDate(), JournalEntryType.CREDIT.getValue().longValue(), + savingsAccountTransactionData.getAmount(), null, JournalEntryType.CREDIT.getValue().longValue(), + savingsAccountData.getId(), DateUtils.getOffsetDateTimeOfTenant(), + DateUtils.getOffsetDateTimeOfTenant(), false, BigDecimal.ZERO, BigDecimal.ZERO, null, + savingsAccountTransactionData.getTransactionDate(), null, userId, userId, + DateUtils.getBusinessLocalDate() }); paramsForGLInsertion.add(new Object[] { savingsAccountData.getGlAccountIdForInterestOnSavings(), savingsAccountData.getOfficeId(), null, currencyCode, SAVINGS_TRANSACTION_IDENTIFIER + savingsAccountTransactionData.getId().toString(), savingsAccountTransactionData.getId(), null, false, null, false, - Date.from(savingsAccountTransactionData.getTransactionDate() - .atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant()), - JournalEntryType.DEBIT.getValue().longValue(), savingsAccountTransactionData.getAmount(), null, - JournalEntryType.DEBIT.getValue().longValue(), savingsAccountData.getId(), - Date.from(currentDate.atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant()), - Date.from(currentDate.atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant()), false, - BigDecimal.ZERO, BigDecimal.ZERO, null, - Date.from(savingsAccountTransactionData.getTransactionDate() - .atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant()), - null, Integer.valueOf(1), Integer.valueOf(1) }); + savingsAccountTransactionData.getTransactionDate(), JournalEntryType.DEBIT.getValue().longValue(), + savingsAccountTransactionData.getAmount(), null, JournalEntryType.DEBIT.getValue().longValue(), + savingsAccountData.getId(), DateUtils.getOffsetDateTimeOfTenant(), + DateUtils.getOffsetDateTimeOfTenant(), false, BigDecimal.ZERO, BigDecimal.ZERO, null, + savingsAccountTransactionData.getTransactionDate(), null, userId, userId, + DateUtils.getBusinessLocalDate() }); } } } @@ -232,10 +226,10 @@ public class SavingsSchedularInterestPoster implements Callable { query.append("INSERT INTO acc_gl_journal_entry(account_id,office_id,reversal_id,currency_code,transaction_id,"); query.append("savings_transaction_id,client_transaction_id,reversed,ref_num,manual_entry,entry_date,type_enum,"); - query.append("amount,description,entity_type_enum,entity_id,created_date,"); - query.append("lastmodified_date,is_running_balance_calculated,office_running_balance,organization_running_balance,"); - query.append("payment_details_id,transaction_date,share_transaction_id, createdby_id, lastmodifiedby_id) "); - query.append("VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + query.append("amount,description,entity_type_enum,entity_id,created_on_utc,"); + query.append("last_modified_on_utc,is_running_balance_calculated,office_running_balance,organization_running_balance,"); + query.append("payment_details_id,transaction_date,share_transaction_id, created_by, last_modified_by, submitted_on_date) "); + query.append("VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); return query.toString(); } diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml index cb283230e..86ee3e172 100644 --- a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml +++ b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml @@ -44,4 +44,5 @@ + diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0025_add_audit_entries_to_journal_entry.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0025_add_audit_entries_to_journal_entry.xml new file mode 100644 index 000000000..156f83c7a --- /dev/null +++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0025_add_audit_entries_to_journal_entry.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select count(*) from acc_gl_journal_entry + + + + + + + select count(*) from acc_gl_journal_entry + + + + + + + + + + + + + + +