added running balance for journal entries

This commit is contained in:
Pramod Nuthakki
2013-09-27 10:13:18 +05:30
parent c4e92edf99
commit ca6bbcb550
5 changed files with 192 additions and 1 deletions
@@ -0,0 +1,5 @@
ALTER TABLE `acc_gl_journal_entry`
ADD COLUMN `is_running_balance_caculated` TINYINT NOT NULL DEFAULT '0' AFTER `lastmodified_date`,
ADD COLUMN `office_running_balance` DECIMAL(19,6) NOT NULL DEFAULT '0.000000' AFTER `is_running_balance_caculated`;
INSERT INTO `job` (`name`, `display_name`, `cron_expression`, `create_time`, `task_priority`, `group_name`, `previous_run_start_time`, `next_run_time`, `job_key`, `initializing_errorlog`, `is_active`, `currently_running`, `updates_allowed`, `scheduler_group`, `is_misfired`) VALUES ('Update Accounting Running Balances', 'Update Accounting Running Balances', '0 1 0 1/1 * ? *', now(), 5, NULL, NULL, NULL, NULL, NULL, 1, 0, 1, 0, 0);
@@ -87,4 +87,29 @@ public class JournalEntryData {
this.referenceNumber = referenceNumber;
}
public Long getId() {
return this.id;
}
public Long getGlAccountId() {
return this.glAccountId;
}
public EnumOptionData getGlAccountType() {
return this.glAccountType;
}
public BigDecimal getAmount() {
return this.amount;
}
public EnumOptionData getEntryType() {
return this.entryType;
}
}
@@ -0,0 +1,8 @@
package org.mifosplatform.accounting.journalentry.service;
public interface JournalEntryRunningBalanceUpdateService {
void updateRunningBalance();
}
@@ -0,0 +1,153 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.accounting.journalentry.service;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.mifosplatform.accounting.common.AccountingEnumerations;
import org.mifosplatform.accounting.glaccount.domain.GLAccountType;
import org.mifosplatform.accounting.journalentry.data.JournalEntryData;
import org.mifosplatform.accounting.journalentry.domain.JournalEntryType;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
import org.mifosplatform.infrastructure.jobs.annotation.CronTarget;
import org.mifosplatform.infrastructure.jobs.service.JobName;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntryRunningBalanceUpdateService {
private final JdbcTemplate jdbcTemplate;
private final GLJournalEntryMapper entryMapper = new GLJournalEntryMapper();
private final String runningBalanceSql = "select je.office_running_balance as runningBalance,je.account_id as accountId from acc_gl_journal_entry je "
+ "inner join (select max(id) as id from acc_gl_journal_entry where office_id=? and entry_date < ? group by account_id,entry_date) je2 "
+ "inner join (select max(entry_date) as date from acc_gl_journal_entry where office_id=? and entry_date < ? group by account_id) je3 "
+ "where je2.id = je.id and je.entry_date = je3.date group by je.id order by je.entry_date DESC";
@Autowired
public JournalEntryRunningBalanceUpdateServiceImpl(final RoutingDataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
@Override
@CronTarget(jobName = JobName.ACCOUNTING_RUNNING_BALANCE_UPDATE)
public void updateRunningBalance() {
String dateFinder = "select je.office_id as officeId,MIN(je.entry_date) as entityDate " + "from acc_gl_journal_entry je "
+ "where je.is_running_balance_caculated=0 " + "group by je.office_id";
List<Map<String, Object>> list = jdbcTemplate.queryForList(dateFinder);
for (Map<String, Object> entries : list) {
Long officeId = (Long) entries.get("officeId");
Date entityDate = (Date) entries.get("entityDate");
updateRunningBalance(officeId, entityDate);
}
}
@Transactional
private void updateRunningBalance(Long officeId, Date entityDate) {
Map<Long, BigDecimal> runningBalanceMap = new HashMap<Long, BigDecimal>(5);
List<Map<String, Object>> list = jdbcTemplate.queryForList(runningBalanceSql, officeId, entityDate, officeId, entityDate);
for (Map<String, Object> entries : list) {
Long accountId = (Long) entries.get("accountId");
if (!runningBalanceMap.containsKey(accountId)) {
runningBalanceMap.put(accountId, (BigDecimal) entries.get("runningBalance"));
}
}
List<JournalEntryData> entryDatas = jdbcTemplate.query(entryMapper.schema(), entryMapper, new Object[] { officeId, entityDate });
String[] updateSql = new String[entryDatas.size()];
int i = 0;
for (JournalEntryData entryData : entryDatas) {
BigDecimal runningBalance = calculateRunningBalance(entryData, runningBalanceMap);
String sql = "UPDATE acc_gl_journal_entry je SET je.is_running_balance_caculated=1, je.office_running_balance="
+ runningBalance + " WHERE je.id=" + entryData.getId();
updateSql[i++] = sql;
}
this.jdbcTemplate.batchUpdate(updateSql);
}
private BigDecimal calculateRunningBalance(JournalEntryData entry, Map<Long, BigDecimal> runningBalanceMap) {
BigDecimal runningBalance = BigDecimal.ZERO;
if (runningBalanceMap.containsKey(entry.getGlAccountId())) {
runningBalance = runningBalanceMap.get(entry.getGlAccountId());
}
GLAccountType accounttype = GLAccountType.fromInt(entry.getGlAccountType().getId().intValue());
JournalEntryType entryType = JournalEntryType.fromInt(entry.getEntryType().getId().intValue());
boolean isIncrease = false;
switch (accounttype) {
case ASSET:
if (entryType.isDebitType()) {
isIncrease = true;
}
break;
case EQUITY:
if (entryType.isCreditType()) {
isIncrease = true;
}
break;
case EXPENSE:
if (entryType.isDebitType()) {
isIncrease = true;
}
break;
case INCOME:
if (entryType.isCreditType()) {
isIncrease = true;
}
break;
case LIABILITY:
if (entryType.isCreditType()) {
isIncrease = true;
}
break;
}
if (isIncrease) {
runningBalance = runningBalance.add(entry.getAmount());
} else {
runningBalance = runningBalance.subtract(entry.getAmount());
}
runningBalanceMap.put(entry.getGlAccountId(), runningBalance);
return runningBalance;
}
private static final class GLJournalEntryMapper implements RowMapper<JournalEntryData> {
public String schema() {
return "select je.id as id,je.account_id as glAccountId," + "je.type_enum as entryType,je.amount as amount, "
+ "glAccount.classification_enum as classification " + "from acc_gl_journal_entry je , acc_gl_account glAccount "
+ "where je.account_id = glAccount.id " + "and je.office_id=? and je.entry_date >= ? order by je.entry_date,je.id";
}
@Override
public JournalEntryData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final Long glAccountId = rs.getLong("glAccountId");
final int accountTypeId = JdbcSupport.getInteger(rs, "classification");
final EnumOptionData accountType = AccountingEnumerations.gLAccountType(accountTypeId);
final BigDecimal amount = rs.getBigDecimal("amount");
final int entryTypeId = JdbcSupport.getInteger(rs, "entryType");
final EnumOptionData entryType = AccountingEnumerations.journalEntryType(entryTypeId);
return new JournalEntryData(id, null, null, null, glAccountId, null, accountType, null, entryType, amount, null, null, null,
null, null, null, null, null, null, null);
}
}
}
@@ -5,7 +5,7 @@ public enum JobName {
UPDATE_LOAN_SUMMARY("Update loan Summary"), UPDATE_LOAN_ARREARS_AGEING("Update Loan Arrears Ageing"), UPDATE_LOAN_PAID_IN_ADVANCE(
"Update Loan Paid In Advance"), APPLY_ANNUAL_FEE_FOR_SAVINGS("Apply Annual Fee For Savings"), APPLY_HOLIDAYS_TO_LOANS(
"Apply Holidays To Loans"), POST_INTEREST_FOR_SAVINGS("Post Interest For Savings"), TRANSFER_FEE_CHARGE_FOR_LOANS(
"Transfer Fee For Loans From Savings");
"Transfer Fee For Loans From Savings"), ACCOUNTING_RUNNING_BALANCE_UPDATE("Update Accounting Running Balances");
private final String name;