Merge pull request #615 from pramodn02/MIFOSX-435_2

Mifosx 435 2
This commit is contained in:
Vishwas Babu A J
2013-10-02 14:49:53 -07:00
12 changed files with 365 additions and 51 deletions
+79 -5
View File
@@ -711,7 +711,8 @@
<tr class="alt"> <tr class="alt">
<td><a href="#journalentries">Journal Entries</a></td> <td><a href="#journalentries">Journal Entries</a></td>
<td>journalentries</td> <td>journalentries</td>
<td><a href="#journalentries_create">Create Journal Entries</a></td> <td><a href="#journalentries_create">Create Journal Entries</a><br>
<a href="#journalentries_updatebalance">Update Journal Entries Running Balance</a></td>
<td><a href="#journalentries_list">List Journal Entries</a></td> <td><a href="#journalentries_list">List Journal Entries</a></td>
<td></td> <td></td>
<td></td> <td></td>
@@ -18734,6 +18735,27 @@ No Request Body:
<tr> <tr>
<td class=fielddesc>Denotes the accounting rule id for posting journal entries. <td class=fielddesc>Denotes the accounting rule id for posting journal entries.
</td> </td>
</tr>
<tr class=alt>
<td>officeRunningBalance</td>
</tr>
<tr>
<td class=fielddesc>Describes office balance after the journal entry for the Ledger Account.
</td>
</tr>
<tr class=alt>
<td>organizationRunningBalance</td>
</tr>
<tr>
<td class=fielddesc>Describes complete organization balances after the journal entry for the Ledger Account.
</td>
</tr>
<tr class=alt>
<td>runningBalanceComputed</td>
</tr>
<tr>
<td class=fielddesc>Describes whether account balances computed for the journal entry.
</td>
</tr> </tr>
</table> </table>
</div> </div>
@@ -18869,7 +18891,10 @@ GET https://DomainName/api/v1/journalentries?transactionId=PB37X8Y21EQUY4S
5 5
], ],
"createdByUserName": "mifos", "createdByUserName": "mifos",
"reversed": false "reversed": false,
"officeRunningBalance":0,
"organizationRunningBalance":0
"runningBalanceComputed":false
}, },
{ {
"id": 2, "id": 2,
@@ -18909,7 +18934,11 @@ GET https://DomainName/api/v1/journalentries?transactionId=PB37X8Y21EQUY4S
5 5
], ],
"createdByUserName": "mifos", "createdByUserName": "mifos",
"reversed": false "reversed": false,
"officeRunningBalance":0,
"organizationRunningBalance":0
"runningBalanceComputed":false
} }
] ]
} }
@@ -19100,6 +19129,46 @@ Request Body:
</div> </div>
</div> </div>
<a id="journalentries_updatebalance" name="journalentries_updatebalance" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Update Running balances for Journal Entries</h4>
<p>
This API calculates the running balances for office. If office ID not provided this API calculates running balances for all offices.
<br>
</p>
<table class=matrixHeading>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Mandatory Fields</div></td>
</tr>
<tr class=alt>
<td>officeId
</td>
</tr>
</table>
</div>
<div class="method-example">
<code class="method-declaration">
POST https://DomainName/api/v1/journalentries?command=updateRunningBalance
</code>
<code class="method-request">
POST journalentries
Content-Type: application/json
Request Body:
{
"officeId": 1,
}
</code>
<code class="method-response">
{
"officeId": 1,
}
</code>
</div>
</div>
<a id="journalentries_retrieve" name="journalentries_retrieve" <a id="journalentries_retrieve" name="journalentries_retrieve"
class="old-syle-anchor">&nbsp;</a> class="old-syle-anchor">&nbsp;</a>
<div class="method-section"> <div class="method-section">
@@ -19149,7 +19218,11 @@ GET https://DomainName/api/v1/journalentries/{entryId}
2 2
], ],
"createdByUserName": "mifos", "createdByUserName": "mifos",
"reversed": false "reversed": false,
"officeRunningBalance":0,
"organizationRunningBalance":0
"runningBalanceComputed":false
} }
</code> </code>
</div> </div>
@@ -19797,7 +19870,8 @@ GET https://DomainName/api/v1/search?query=000000111
<tr class="alt"> <tr class="alt">
<td><a href="#journalentries">Journal Entries</a></td> <td><a href="#journalentries">Journal Entries</a></td>
<td>journalentries</td> <td>journalentries</td>
<td><a href="#journalentries_create">Create Journal Entries</a></td> <td><a href="#journalentries_create">Create Journal Entries</a><br>
<a href="#journalentries_updatebalance">Update Journal Entries Running Balance</a></td>
<td><a href="#journalentries_list">List Journal Entries</a></td> <td><a href="#journalentries_list">List Journal Entries</a></td>
<td></td> <td></td>
<td></td> <td></td>
@@ -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);
@@ -116,12 +116,17 @@ public class JournalEntriesApiResource {
@POST @POST
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String createGLJournalEntry(final String jsonRequestBody) { public String createGLJournalEntry(final String jsonRequestBody, @QueryParam("command") final String commandParam) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().createJournalEntry().withJson(jsonRequestBody).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
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); return this.apiJsonSerializerService.serialize(result);
} }
@@ -12,14 +12,13 @@ import org.mifosplatform.infrastructure.core.data.EnumOptionData;
/** /**
* Immutable object representing a General Ledger Account * Immutable object representing a General Ledger Account
* *
* Note: no getter/setters required as google will produce json from fields of * Note: no getter/setters required as google will produce json from fields of
* object. * object.
*/ */
public class JournalEntryData { public class JournalEntryData {
private final Long id; private final Long id;
@SuppressWarnings("unused")
private final Long officeId; private final Long officeId;
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final String officeName; private final String officeName;
@@ -53,13 +52,20 @@ public class JournalEntryData {
private final Boolean reversed; private final Boolean reversed;
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final String referenceNumber; 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, public JournalEntryData(final Long id, final Long officeId, final String officeName, final String glAccountName,
final Long glAccountId, final String glAccountCode, final EnumOptionData glAccountClassification, final Long glAccountId, final String glAccountCode, final EnumOptionData glAccountClassification,
final LocalDate transactionDate, final EnumOptionData entryType, final BigDecimal amount, final String transactionId, 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 Boolean manualEntry, final EnumOptionData entityType, final Long entityId, final Long createdByUserId,
final LocalDate createdDate, final String createdByUserName, final String comments, final Boolean reversed, 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.id = id;
this.officeId = officeId; this.officeId = officeId;
this.officeName = officeName; this.officeName = officeName;
@@ -80,22 +86,22 @@ public class JournalEntryData {
this.comments = comments; this.comments = comments;
this.reversed = reversed; this.reversed = reversed;
this.referenceNumber = referenceNumber; this.referenceNumber = referenceNumber;
this.officeRunningBalance = officeRunningBalance;
this.organizationRunningBalance = organizationRunningBalance;
this.runningBalanceComputed = runningBalanceComputed;
} }
public Long getId() {
return this.id;
}
public Long getId() { public Long getGlAccountId() {
return this.id; return this.glAccountId;
} }
public EnumOptionData getGlAccountType() {
public Long getGlAccountId() { return this.glAccountType;
return this.glAccountId; }
}
public EnumOptionData getGlAccountType() {
return this.glAccountType;
}
public BigDecimal getAmount() { public BigDecimal getAmount() {
return this.amount; return this.amount;
@@ -104,4 +110,8 @@ public class JournalEntryData {
public EnumOptionData getEntryType() { public EnumOptionData getEntryType() {
return this.entryType; return this.entryType;
} }
public Long getOfficeId() {
return this.officeId;
}
} }
@@ -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<String> RUNNING_BALANCE_UPDATE_REQUEST_DATA_PARAMETERS = new HashSet<String>(
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<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, command.json(), RUNNING_BALANCE_UPDATE_REQUEST_DATA_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
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); }
}
}
@@ -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);
}
}
@@ -53,7 +53,10 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
+ " journalEntry.type_enum as entryType,journalEntry.amount as amount, journalEntry.transaction_id as transactionId," + " 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, " + " journalEntry.entity_type_enum as entityType, journalEntry.entity_id as entityId, creatingUser.id as createdByUserId, "
+ " creatingUser.username as createdByUserName, journalEntry.description as comments, " + " 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 " + " from acc_gl_journal_entry journalEntry, acc_gl_account glAccount, m_office office, m_appuser creatingUser "
+ " where journalEntry.account_id = glAccount.id " + " where journalEntry.account_id = glAccount.id "
+ " and journalEntry.office_id = office.id and journalEntry.createdby_id = creatingUser.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 String comments = rs.getString("comments");
final Boolean reversed = rs.getBoolean("reversed"); final Boolean reversed = rs.getBoolean("reversed");
final String referenceNumber = rs.getString("referenceNumber"); 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, return new JournalEntryData(id, officeId, officeName, glAccountName, glAccountId, glCode, accountType, transactionDate,
entryType, amount, transactionId, manualEntry, entityType, entityId, createdByUserId, createdDate, createdByUserName, entryType, amount, transactionId, manualEntry, entityType, entityId, createdByUserId, createdDate, createdByUserName,
comments, reversed, referenceNumber); comments, reversed, referenceNumber,officeRunningBalance,organizationRunningBalance,runningBalanceComputed);
} }
} }
@@ -1,8 +1,12 @@
package org.mifosplatform.accounting.journalentry.service; package org.mifosplatform.accounting.journalentry.service;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
public interface JournalEntryRunningBalanceUpdateService { public interface JournalEntryRunningBalanceUpdateService {
void updateRunningBalance(); void updateRunningBalance();
CommandProcessingResult updateOfficeRunningBalance(JsonCommand command);
} }
@@ -15,14 +15,26 @@ import java.util.Map;
import org.mifosplatform.accounting.common.AccountingEnumerations; import org.mifosplatform.accounting.common.AccountingEnumerations;
import org.mifosplatform.accounting.glaccount.domain.GLAccountType; 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.JournalEntryData;
import org.mifosplatform.accounting.journalentry.data.JournalEntryDataValidator;
import org.mifosplatform.accounting.journalentry.domain.JournalEntryType; 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.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport; 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.core.service.RoutingDataSource;
import org.mifosplatform.infrastructure.jobs.annotation.CronTarget; import org.mifosplatform.infrastructure.jobs.annotation.CronTarget;
import org.mifosplatform.infrastructure.jobs.service.JobName; 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.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -31,52 +43,151 @@ import org.springframework.transaction.annotation.Transactional;
@Service @Service
public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntryRunningBalanceUpdateService { public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntryRunningBalanceUpdateService {
private final static Logger logger = LoggerFactory.getLogger(JournalEntryRunningBalanceUpdateServiceImpl.class);
private final JdbcTemplate jdbcTemplate; private final JdbcTemplate jdbcTemplate;
private final OfficeRepository officeRepository;
private final JournalEntryDataValidator dataValidator;
private final FromJsonHelper fromApiJsonHelper;
private final GLJournalEntryMapper entryMapper = new GLJournalEntryMapper(); 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(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 " + "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"; + "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 @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.jdbcTemplate = new JdbcTemplate(dataSource);
this.officeRepository = officeRepository;
this.dataValidator = dataValidator;
this.fromApiJsonHelper = fromApiJsonHelper;
} }
@Override @Override
@CronTarget(jobName = JobName.ACCOUNTING_RUNNING_BALANCE_UPDATE) @CronTarget(jobName = JobName.ACCOUNTING_RUNNING_BALANCE_UPDATE)
public void updateRunningBalance() { public void updateRunningBalance() {
String dateFinder = "select MIN(je.entry_date) as entityDate from acc_gl_journal_entry je "
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 ";
+ "where je.is_running_balance_caculated=0 " + "group by je.office_id"; try {
List<Map<String, Object>> list = jdbcTemplate.queryForList(dateFinder); Date entityDate = this.jdbcTemplate.queryForObject(dateFinder, Date.class);
for (Map<String, Object> entries : list) { updateOrganizationRunningBalance(entityDate);
Long officeId = (Long) entries.get("officeId"); } catch (EmptyResultDataAccessException e) {
Date entityDate = (Date) entries.get("entityDate"); logger.debug("No results found for updation of running balance ");
updateRunningBalance(officeId, entityDate);
} }
} }
@Transactional @Override
private void updateRunningBalance(Long officeId, Date entityDate) { public CommandProcessingResult updateOfficeRunningBalance(JsonCommand command) {
Map<Long, BigDecimal> runningBalanceMap = new HashMap<Long, BigDecimal>(5); 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<Map<String, Object>> 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<Long, BigDecimal> runningBalanceMap = new HashMap<Long, BigDecimal>(5);
Map<Long, Map<Long, BigDecimal>> officesRunningBalance = new HashMap<Long, Map<Long, BigDecimal>>();
List<Map<String, Object>> list = jdbcTemplate.queryForList(organizationRunningBalanceSql, entityDate, entityDate);
for (Map<String, Object> entries : list) { for (Map<String, Object> entries : list) {
Long accountId = (Long) entries.get("accountId"); Long accountId = (Long) entries.get("accountId");
if (!runningBalanceMap.containsKey(accountId)) { if (!runningBalanceMap.containsKey(accountId)) {
runningBalanceMap.put(accountId, (BigDecimal) entries.get("runningBalance")); runningBalanceMap.put(accountId, (BigDecimal) entries.get("runningBalance"));
} }
} }
List<JournalEntryData> entryDatas = jdbcTemplate.query(entryMapper.schema(), entryMapper, new Object[] { officeId, entityDate });
List<Map<String, Object>> officesRunningBalanceList = jdbcTemplate.queryForList(officesRunningBalanceSql, entityDate, entityDate);
for (Map<String, Object> entries : officesRunningBalanceList) {
Long accountId = (Long) entries.get("accountId");
Long officeId = (Long) entries.get("officeId");
Map<Long, BigDecimal> runningBalance = null;
if (officesRunningBalance.containsKey(officeId)) {
runningBalance = officesRunningBalance.get(officeId);
} else {
runningBalance = new HashMap<Long, BigDecimal>();
officesRunningBalance.put(officeId, runningBalance);
}
if (!runningBalance.containsKey(accountId)) {
runningBalance.put(accountId, (BigDecimal) entries.get("runningBalance"));
}
}
List<JournalEntryData> entryDatas = jdbcTemplate.query(entryMapper.organizationRunningBalanceSchema(), entryMapper,
new Object[] { entityDate });
String[] updateSql = new String[entryDatas.size()];
int i = 0;
for (JournalEntryData entryData : entryDatas) {
Map<Long, BigDecimal> officeRunningBalanceMap = null;
if (officesRunningBalance.containsKey(entryData.getOfficeId())) {
officeRunningBalanceMap = officesRunningBalance.get(entryData.getOfficeId());
} else {
officeRunningBalanceMap = new HashMap<Long, BigDecimal>();
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<Long, BigDecimal> runningBalanceMap = new HashMap<Long, BigDecimal>(5);
List<Map<String, Object>> list = jdbcTemplate.queryForList(officeRunningBalanceSql, 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.officeRunningBalanceSchema(), entryMapper, new Object[] {
officeId, entityDate });
String[] updateSql = new String[entryDatas.size()]; String[] updateSql = new String[entryDatas.size()];
int i = 0; int i = 0;
for (JournalEntryData entryData : entryDatas) { for (JournalEntryData entryData : entryDatas) {
BigDecimal runningBalance = calculateRunningBalance(entryData, runningBalanceMap); BigDecimal runningBalance = calculateRunningBalance(entryData, runningBalanceMap);
String sql = "UPDATE acc_gl_journal_entry je SET je.is_running_balance_caculated=1, je.office_running_balance=" String sql = "UPDATE acc_gl_journal_entry je SET je.office_running_balance=" + runningBalance + " WHERE je.id="
+ runningBalance + " WHERE je.id=" + entryData.getId(); + entryData.getId();
updateSql[i++] = sql; updateSql[i++] = sql;
} }
this.jdbcTemplate.batchUpdate(updateSql); this.jdbcTemplate.batchUpdate(updateSql);
@@ -128,10 +239,18 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry
private static final class GLJournalEntryMapper implements RowMapper<JournalEntryData> { private static final class GLJournalEntryMapper implements RowMapper<JournalEntryData> {
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, " 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 " + "glAccount.classification_enum as classification,je.office_id as officeId "
+ "where je.account_id = glAccount.id " + "and je.office_id=? and je.entry_date >= ? order by je.entry_date,je.id"; + "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 @Override
@@ -139,14 +258,15 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry
final Long id = rs.getLong("id"); final Long id = rs.getLong("id");
final Long glAccountId = rs.getLong("glAccountId"); final Long glAccountId = rs.getLong("glAccountId");
final Long officeId = rs.getLong("officeId");
final int accountTypeId = JdbcSupport.getInteger(rs, "classification"); final int accountTypeId = JdbcSupport.getInteger(rs, "classification");
final EnumOptionData accountType = AccountingEnumerations.gLAccountType(accountTypeId); final EnumOptionData accountType = AccountingEnumerations.gLAccountType(accountTypeId);
final BigDecimal amount = rs.getBigDecimal("amount"); final BigDecimal amount = rs.getBigDecimal("amount");
final int entryTypeId = JdbcSupport.getInteger(rs, "entryType"); final int entryTypeId = JdbcSupport.getInteger(rs, "entryType");
final EnumOptionData entryType = AccountingEnumerations.journalEntryType(entryTypeId); final EnumOptionData entryType = AccountingEnumerations.journalEntryType(entryTypeId);
return new JournalEntryData(id, null, 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);
} }
} }
@@ -262,6 +262,10 @@ public class CommandWrapper {
return this.actionName.equalsIgnoreCase("REVERSE") && this.entityName.equalsIgnoreCase("JOURNALENTRY"); return this.actionName.equalsIgnoreCase("REVERSE") && this.entityName.equalsIgnoreCase("JOURNALENTRY");
} }
public boolean isUpdateRunningbalance() {
return this.actionName.equalsIgnoreCase("UPDATERUNNINGBALANCE") && this.entityName.equalsIgnoreCase("JOURNALENTRY");
}
public boolean isFundResource() { public boolean isFundResource() {
return this.entityName.equalsIgnoreCase("FUND"); return this.entityName.equalsIgnoreCase("FUND");
} }
@@ -773,6 +773,15 @@ public class CommandWrapperBuilder {
this.href = "/journalentries/" + transactionId; this.href = "/journalentries/" + transactionId;
return this; return this;
} }
public CommandWrapperBuilder updateRunningBalanceForJournalEntry() {
this.actionName = "UPDATERUNNINGBALANCE";
this.entityName = "JOURNALENTRY";
this.entityId = null;
this.href = "/journalentries/update";
return this;
}
public CommandWrapperBuilder createSavingProduct() { public CommandWrapperBuilder createSavingProduct() {
this.actionName = "CREATE"; this.actionName = "CREATE";
@@ -376,7 +376,9 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
handler = this.applicationContext.getBean("createJournalEntryCommandHandler", NewCommandSourceHandler.class); handler = this.applicationContext.getBean("createJournalEntryCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isRevertJournalEntry()) { } else if (wrapper.isRevertJournalEntry()) {
handler = this.applicationContext.getBean("reverseJournalEntryCommandHandler", NewCommandSourceHandler.class); 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()); throw new UnsupportedCommandException(wrapper.commandName());
} }
} else if (wrapper.isSavingsProductResource()) { } else if (wrapper.isSavingsProductResource()) {