diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index 80ebad7ea..fd329efd9 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -711,7 +711,8 @@ Journal Entries journalentries - Create Journal Entries + Create Journal Entries
+ Update Journal Entries Running Balance List Journal Entries @@ -18734,6 +18735,27 @@ No Request Body: Denotes the accounting rule id for posting journal entries. + + + officeRunningBalance + + + Describes office balance after the journal entry for the Ledger Account. + + + + organizationRunningBalance + + + Describes complete organization balances after the journal entry for the Ledger Account. + + + + runningBalanceComputed + + + Describes whether account balances computed for the journal entry. + @@ -18869,7 +18891,10 @@ GET https://DomainName/api/v1/journalentries?transactionId=PB37X8Y21EQUY4S 5 ], "createdByUserName": "mifos", - "reversed": false + "reversed": false, + "officeRunningBalance":0, + "organizationRunningBalance":0 + "runningBalanceComputed":false }, { "id": 2, @@ -18909,7 +18934,11 @@ GET https://DomainName/api/v1/journalentries?transactionId=PB37X8Y21EQUY4S 5 ], "createdByUserName": "mifos", - "reversed": false + "reversed": false, + "officeRunningBalance":0, + "organizationRunningBalance":0 + "runningBalanceComputed":false + } ] } @@ -19100,6 +19129,46 @@ Request Body: +   +
+
+

Update Running balances for Journal Entries

+

+ This API calculates the running balances for office. If office ID not provided this API calculates running balances for all offices. +
+

+ + + + + + + +
Mandatory Fields
officeId +
+
+
+ +POST https://DomainName/api/v1/journalentries?command=updateRunningBalance + + +POST journalentries +Content-Type: application/json +Request Body: +{ +"officeId": 1, +} + + +{ + "officeId": 1, +} + + +
+
+ +  
@@ -19149,7 +19218,11 @@ GET https://DomainName/api/v1/journalentries/{entryId} 2 ], "createdByUserName": "mifos", - "reversed": false + "reversed": false, + "officeRunningBalance":0, + "organizationRunningBalance":0 + "runningBalanceComputed":false + }
@@ -19797,7 +19870,8 @@ GET https://DomainName/api/v1/search?query=000000111 Journal Entries journalentries - Create Journal Entries + Create Journal Entries
+ Update Journal Entries Running Balance List Journal Entries diff --git a/mifosng-db/migrations/core_db/V121__accounting_running_balance_for_organization.sql b/mifosng-db/migrations/core_db/V121__accounting_running_balance_for_organization.sql new file mode 100755 index 000000000..71aa9eaac --- /dev/null +++ b/mifosng-db/migrations/core_db/V121__accounting_running_balance_for_organization.sql @@ -0,0 +1,4 @@ +ALTER TABLE `acc_gl_journal_entry` + ADD COLUMN `organization_running_balance` DECIMAL(19,6) NOT NULL DEFAULT '0.000000' AFTER `office_running_balance`; + +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('accounting', 'UPDATERUNNINGBALANCE_JOURNALENTRY', 'JOURNALENTRY', 'UPDATERUNNINGBALANCE', 0); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/api/JournalEntriesApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/api/JournalEntriesApiResource.java index 2dd5abff7..2cc803a8c 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/api/JournalEntriesApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/api/JournalEntriesApiResource.java @@ -116,12 +116,17 @@ public class JournalEntriesApiResource { @POST @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) - public String createGLJournalEntry(final String jsonRequestBody) { - - final CommandWrapper commandRequest = new CommandWrapperBuilder().createJournalEntry().withJson(jsonRequestBody).build(); - - final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + public String createGLJournalEntry(final String jsonRequestBody, @QueryParam("command") final String commandParam) { + CommandProcessingResult result = null; + if (is(commandParam, "updateRunningBalance")) { + final CommandWrapper commandRequest = new CommandWrapperBuilder().updateRunningBalanceForJournalEntry() + .withJson(jsonRequestBody).build(); + result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + } else { + final CommandWrapper commandRequest = new CommandWrapperBuilder().createJournalEntry().withJson(jsonRequestBody).build(); + result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + } return this.apiJsonSerializerService.serialize(result); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/JournalEntryData.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/JournalEntryData.java index 8ae533e9f..37ddd242d 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/JournalEntryData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/JournalEntryData.java @@ -12,14 +12,13 @@ import org.mifosplatform.infrastructure.core.data.EnumOptionData; /** * Immutable object representing a General Ledger Account - * + * * Note: no getter/setters required as google will produce json from fields of * object. */ public class JournalEntryData { private final Long id; - @SuppressWarnings("unused") private final Long officeId; @SuppressWarnings("unused") private final String officeName; @@ -53,13 +52,20 @@ public class JournalEntryData { private final Boolean reversed; @SuppressWarnings("unused") private final String referenceNumber; + @SuppressWarnings("unused") + private final BigDecimal officeRunningBalance; + @SuppressWarnings("unused") + private final BigDecimal organizationRunningBalance; + @SuppressWarnings("unused") + private final Boolean runningBalanceComputed; public JournalEntryData(final Long id, final Long officeId, final String officeName, final String glAccountName, final Long glAccountId, final String glAccountCode, final EnumOptionData glAccountClassification, final LocalDate transactionDate, final EnumOptionData entryType, final BigDecimal amount, final String transactionId, final Boolean manualEntry, final EnumOptionData entityType, final Long entityId, final Long createdByUserId, final LocalDate createdDate, final String createdByUserName, final String comments, final Boolean reversed, - final String referenceNumber) { + final String referenceNumber, final BigDecimal officeRunningBalance, final BigDecimal organizationRunningBalance, + final Boolean runningBalanceComputed) { this.id = id; this.officeId = officeId; this.officeName = officeName; @@ -80,22 +86,22 @@ public class JournalEntryData { this.comments = comments; this.reversed = reversed; this.referenceNumber = referenceNumber; + this.officeRunningBalance = officeRunningBalance; + this.organizationRunningBalance = organizationRunningBalance; + this.runningBalanceComputed = runningBalanceComputed; } + public Long getId() { + return this.id; + } - public Long getId() { - return this.id; - } + public Long getGlAccountId() { + return this.glAccountId; + } - - public Long getGlAccountId() { - return this.glAccountId; - } - - - public EnumOptionData getGlAccountType() { - return this.glAccountType; - } + public EnumOptionData getGlAccountType() { + return this.glAccountType; + } public BigDecimal getAmount() { return this.amount; @@ -104,4 +110,8 @@ public class JournalEntryData { public EnumOptionData getEntryType() { return this.entryType; } + + public Long getOfficeId() { + return this.officeId; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/JournalEntryDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/JournalEntryDataValidator.java new file mode 100755 index 000000000..f6583fff7 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/JournalEntryDataValidator.java @@ -0,0 +1,51 @@ +package org.mifosplatform.accounting.journalentry.data; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.mifosplatform.accounting.journalentry.api.JournalEntryJsonInputParams; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.ApiParameterError; +import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; +import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; +import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.google.gson.reflect.TypeToken; + +@Component +public class JournalEntryDataValidator { + + private final FromJsonHelper fromApiJsonHelper; + + public static final Set RUNNING_BALANCE_UPDATE_REQUEST_DATA_PARAMETERS = new HashSet( + Arrays.asList(JournalEntryJsonInputParams.OFFICE_ID.getValue())); + + @Autowired + public JournalEntryDataValidator(final FromJsonHelper fromApiJsonHelper) { + this.fromApiJsonHelper = fromApiJsonHelper; + } + + public void validateForUpdateRunningbalance(final JsonCommand command) { + final Type typeOfMap = new TypeToken>() {}.getType(); + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, command.json(), RUNNING_BALANCE_UPDATE_REQUEST_DATA_PARAMETERS); + final List dataValidationErrors = new ArrayList(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("GLJournalEntry"); + + if (this.fromApiJsonHelper.parameterExists(JournalEntryJsonInputParams.OFFICE_ID.getValue(), command.parsedJson())) { + final String officeId = this.fromApiJsonHelper.extractStringNamed(JournalEntryJsonInputParams.OFFICE_ID.getValue(), + command.parsedJson()); + baseDataValidator.reset().parameter(JournalEntryJsonInputParams.OFFICE_ID.getValue()).value(officeId).ignoreIfNull() + .longGreaterThanZero(); + } + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); } + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/handler/UpdateRunningBalanceCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/handler/UpdateRunningBalanceCommandHandler.java new file mode 100755 index 000000000..23b678a64 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/handler/UpdateRunningBalanceCommandHandler.java @@ -0,0 +1,25 @@ +package org.mifosplatform.accounting.journalentry.handler; + +import org.mifosplatform.accounting.journalentry.service.JournalEntryRunningBalanceUpdateService; +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class UpdateRunningBalanceCommandHandler implements NewCommandSourceHandler { + + private final JournalEntryRunningBalanceUpdateService journalEntryRunningBalanceUpdateService; + + @Autowired + public UpdateRunningBalanceCommandHandler(final JournalEntryRunningBalanceUpdateService journalEntryRunningBalanceUpdateService) { + this.journalEntryRunningBalanceUpdateService = journalEntryRunningBalanceUpdateService; + } + + @Override + public CommandProcessingResult processCommand(JsonCommand command) { + return journalEntryRunningBalanceUpdateService.updateOfficeRunningBalance(command); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryReadPlatformServiceImpl.java index 17f65e6c9..b47f55b55 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryReadPlatformServiceImpl.java @@ -53,7 +53,10 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat + " journalEntry.type_enum as entryType,journalEntry.amount as amount, journalEntry.transaction_id as transactionId," + " journalEntry.entity_type_enum as entityType, journalEntry.entity_id as entityId, creatingUser.id as createdByUserId, " + " creatingUser.username as createdByUserName, journalEntry.description as comments, " - + " journalEntry.created_date as createdDate, journalEntry.reversed as reversed " + + " journalEntry.created_date as createdDate, journalEntry.reversed as reversed, " + + " journalEntry.is_running_balance_caculated as runningBalanceComputed, " + + " journalEntry.office_running_balance as officeRunningBalance, " + + " journalEntry.organization_running_balance as organizationRunningBalance " + " from acc_gl_journal_entry journalEntry, acc_gl_account glAccount, m_office office, m_appuser creatingUser " + " where journalEntry.account_id = glAccount.id " + " and journalEntry.office_id = office.id and journalEntry.createdby_id = creatingUser.id "; @@ -89,10 +92,13 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat final String comments = rs.getString("comments"); final Boolean reversed = rs.getBoolean("reversed"); final String referenceNumber = rs.getString("referenceNumber"); + final BigDecimal officeRunningBalance = rs.getBigDecimal("officeRunningBalance"); + final BigDecimal organizationRunningBalance = rs.getBigDecimal("organizationRunningBalance"); + final Boolean runningBalanceComputed = rs.getBoolean("runningBalanceComputed"); return new JournalEntryData(id, officeId, officeName, glAccountName, glAccountId, glCode, accountType, transactionDate, entryType, amount, transactionId, manualEntry, entityType, entityId, createdByUserId, createdDate, createdByUserName, - comments, reversed, referenceNumber); + comments, reversed, referenceNumber,officeRunningBalance,organizationRunningBalance,runningBalanceComputed); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryRunningBalanceUpdateService.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryRunningBalanceUpdateService.java index b8c0f20a8..70d454857 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryRunningBalanceUpdateService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryRunningBalanceUpdateService.java @@ -1,8 +1,12 @@ package org.mifosplatform.accounting.journalentry.service; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; public interface JournalEntryRunningBalanceUpdateService { void updateRunningBalance(); + CommandProcessingResult updateOfficeRunningBalance(JsonCommand command); + } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryRunningBalanceUpdateServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryRunningBalanceUpdateServiceImpl.java index cf9a540ee..972e9037e 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryRunningBalanceUpdateServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryRunningBalanceUpdateServiceImpl.java @@ -15,14 +15,26 @@ import java.util.Map; import org.mifosplatform.accounting.common.AccountingEnumerations; import org.mifosplatform.accounting.glaccount.domain.GLAccountType; +import org.mifosplatform.accounting.journalentry.api.JournalEntryJsonInputParams; import org.mifosplatform.accounting.journalentry.data.JournalEntryData; +import org.mifosplatform.accounting.journalentry.data.JournalEntryDataValidator; import org.mifosplatform.accounting.journalentry.domain.JournalEntryType; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.domain.JdbcSupport; +import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.infrastructure.core.service.RoutingDataSource; import org.mifosplatform.infrastructure.jobs.annotation.CronTarget; import org.mifosplatform.infrastructure.jobs.service.JobName; +import org.mifosplatform.organisation.office.domain.Office; +import org.mifosplatform.organisation.office.domain.OfficeRepository; +import org.mifosplatform.organisation.office.exception.OfficeNotFoundException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Service; @@ -31,52 +43,151 @@ import org.springframework.transaction.annotation.Transactional; @Service public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntryRunningBalanceUpdateService { + private final static Logger logger = LoggerFactory.getLogger(JournalEntryRunningBalanceUpdateServiceImpl.class); + private final JdbcTemplate jdbcTemplate; + private final OfficeRepository officeRepository; + + private final JournalEntryDataValidator dataValidator; + + private final FromJsonHelper fromApiJsonHelper; + 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 " + private final String officeRunningBalanceSql = "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"; + private final String organizationRunningBalanceSql = "select je.organization_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 entry_date < ? group by account_id,entry_date) je2 " + + "inner join (select max(entry_date) as date from acc_gl_journal_entry where 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"; + + private final String officesRunningBalanceSql = "select je.office_running_balance as runningBalance,je.account_id as accountId,je.office_id as officeId " + + "from acc_gl_journal_entry je " + + "inner join (select max(id) as id from acc_gl_journal_entry where entry_date < ? group by office_id,account_id,entry_date) je2 " + + "inner join (select max(entry_date) as date from acc_gl_journal_entry where entry_date < ? group by office_id,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) { + public JournalEntryRunningBalanceUpdateServiceImpl(final RoutingDataSource dataSource, final OfficeRepository officeRepository, + final JournalEntryDataValidator dataValidator, final FromJsonHelper fromApiJsonHelper) { this.jdbcTemplate = new JdbcTemplate(dataSource); + this.officeRepository = officeRepository; + this.dataValidator = dataValidator; + this.fromApiJsonHelper = fromApiJsonHelper; } @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> list = jdbcTemplate.queryForList(dateFinder); - for (Map entries : list) { - Long officeId = (Long) entries.get("officeId"); - Date entityDate = (Date) entries.get("entityDate"); - updateRunningBalance(officeId, entityDate); - + String dateFinder = "select MIN(je.entry_date) as entityDate from acc_gl_journal_entry je " + + "where je.is_running_balance_caculated=0 "; + try { + Date entityDate = this.jdbcTemplate.queryForObject(dateFinder, Date.class); + updateOrganizationRunningBalance(entityDate); + } catch (EmptyResultDataAccessException e) { + logger.debug("No results found for updation of running balance "); } } - @Transactional - private void updateRunningBalance(Long officeId, Date entityDate) { - Map runningBalanceMap = new HashMap(5); + @Override + public CommandProcessingResult updateOfficeRunningBalance(JsonCommand command) { + this.dataValidator.validateForUpdateRunningbalance(command); + final Long officeId = this.fromApiJsonHelper.extractLongNamed(JournalEntryJsonInputParams.OFFICE_ID.getValue(), + command.parsedJson()); + CommandProcessingResultBuilder commandProcessingResultBuilder = new CommandProcessingResultBuilder().withCommandId(command + .commandId()); + if (officeId == null) { + updateRunningBalance(); + } else { + final Office office = this.officeRepository.findOne(officeId); + if (office == null) { throw new OfficeNotFoundException(officeId); } - List> list = jdbcTemplate.queryForList(runningBalanceSql, officeId, entityDate, officeId, entityDate); + String dateFinder = "select MIN(je.entry_date) as entityDate " + "from acc_gl_journal_entry je " + + "where je.is_running_balance_caculated=0 and je.office_id=?"; + try { + Date entityDate = this.jdbcTemplate.queryForObject(dateFinder, Date.class, officeId); + updateRunningBalance(officeId, entityDate); + } catch (EmptyResultDataAccessException e) { + logger.debug("No results found for updation of office running balance with office id:" + officeId); + } + commandProcessingResultBuilder.withOfficeId(officeId); + } + return commandProcessingResultBuilder.build(); + } + + @Transactional + private void updateOrganizationRunningBalance(Date entityDate) { + Map runningBalanceMap = new HashMap(5); + Map> officesRunningBalance = new HashMap>(); + + List> list = jdbcTemplate.queryForList(organizationRunningBalanceSql, entityDate, entityDate); for (Map entries : list) { Long accountId = (Long) entries.get("accountId"); if (!runningBalanceMap.containsKey(accountId)) { runningBalanceMap.put(accountId, (BigDecimal) entries.get("runningBalance")); } } - List entryDatas = jdbcTemplate.query(entryMapper.schema(), entryMapper, new Object[] { officeId, entityDate }); + + List> officesRunningBalanceList = jdbcTemplate.queryForList(officesRunningBalanceSql, entityDate, entityDate); + for (Map entries : officesRunningBalanceList) { + Long accountId = (Long) entries.get("accountId"); + Long officeId = (Long) entries.get("officeId"); + Map runningBalance = null; + if (officesRunningBalance.containsKey(officeId)) { + runningBalance = officesRunningBalance.get(officeId); + } else { + runningBalance = new HashMap(); + officesRunningBalance.put(officeId, runningBalance); + } + if (!runningBalance.containsKey(accountId)) { + runningBalance.put(accountId, (BigDecimal) entries.get("runningBalance")); + } + } + + List entryDatas = jdbcTemplate.query(entryMapper.organizationRunningBalanceSchema(), entryMapper, + new Object[] { entityDate }); + String[] updateSql = new String[entryDatas.size()]; + int i = 0; + for (JournalEntryData entryData : entryDatas) { + Map officeRunningBalanceMap = null; + if (officesRunningBalance.containsKey(entryData.getOfficeId())) { + officeRunningBalanceMap = officesRunningBalance.get(entryData.getOfficeId()); + } else { + officeRunningBalanceMap = new HashMap(); + officesRunningBalance.put(entryData.getOfficeId(), officeRunningBalanceMap); + } + BigDecimal officeRunningBalance = calculateRunningBalance(entryData, officeRunningBalanceMap); + BigDecimal runningBalance = calculateRunningBalance(entryData, runningBalanceMap); + String sql = "UPDATE acc_gl_journal_entry je SET je.is_running_balance_caculated=1, je.organization_running_balance=" + + runningBalance + ",je.office_running_balance=" + officeRunningBalance + " WHERE je.id=" + entryData.getId(); + updateSql[i++] = sql; + } + this.jdbcTemplate.batchUpdate(updateSql); + + } + + @Transactional + private void updateRunningBalance(Long officeId, Date entityDate) { + Map runningBalanceMap = new HashMap(5); + + List> list = jdbcTemplate.queryForList(officeRunningBalanceSql, officeId, entityDate, officeId, entityDate); + for (Map entries : list) { + Long accountId = (Long) entries.get("accountId"); + if (!runningBalanceMap.containsKey(accountId)) { + runningBalanceMap.put(accountId, (BigDecimal) entries.get("runningBalance")); + } + } + List entryDatas = jdbcTemplate.query(entryMapper.officeRunningBalanceSchema(), 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(); + String sql = "UPDATE acc_gl_journal_entry je SET je.office_running_balance=" + runningBalance + " WHERE je.id=" + + entryData.getId(); updateSql[i++] = sql; } this.jdbcTemplate.batchUpdate(updateSql); @@ -128,10 +239,18 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry private static final class GLJournalEntryMapper implements RowMapper { - public String schema() { + public String officeRunningBalanceSchema() { + 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,je.office_id as officeId " + + "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"; + } + + public String organizationRunningBalanceSchema() { 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"; + + "glAccount.classification_enum as classification,je.office_id as officeId " + + "from acc_gl_journal_entry je , acc_gl_account glAccount " + "where je.account_id = glAccount.id " + + "and je.entry_date >= ? order by je.entry_date,je.id"; } @Override @@ -139,14 +258,15 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry final Long id = rs.getLong("id"); final Long glAccountId = rs.getLong("glAccountId"); + final Long officeId = rs.getLong("officeId"); 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); + 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); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java index 793882ded..71d8e8430 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java @@ -262,6 +262,10 @@ public class CommandWrapper { return this.actionName.equalsIgnoreCase("REVERSE") && this.entityName.equalsIgnoreCase("JOURNALENTRY"); } + public boolean isUpdateRunningbalance() { + return this.actionName.equalsIgnoreCase("UPDATERUNNINGBALANCE") && this.entityName.equalsIgnoreCase("JOURNALENTRY"); + } + public boolean isFundResource() { return this.entityName.equalsIgnoreCase("FUND"); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java index cf8b18bc0..af04545fd 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java @@ -773,6 +773,15 @@ public class CommandWrapperBuilder { this.href = "/journalentries/" + transactionId; return this; } + + public CommandWrapperBuilder updateRunningBalanceForJournalEntry() { + this.actionName = "UPDATERUNNINGBALANCE"; + this.entityName = "JOURNALENTRY"; + this.entityId = null; + this.href = "/journalentries/update"; + return this; + } + public CommandWrapperBuilder createSavingProduct() { this.actionName = "CREATE"; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java index aec5f80a4..a05539408 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java @@ -376,7 +376,9 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer handler = this.applicationContext.getBean("createJournalEntryCommandHandler", NewCommandSourceHandler.class); } else if (wrapper.isRevertJournalEntry()) { handler = this.applicationContext.getBean("reverseJournalEntryCommandHandler", NewCommandSourceHandler.class); - } else { + }else if(wrapper.isUpdateRunningbalance()){ + handler = this.applicationContext.getBean("updateRunningBalanceCommandHandler", NewCommandSourceHandler.class); + }else { throw new UnsupportedCommandException(wrapper.commandName()); } } else if (wrapper.isSavingsProductResource()) {