Merge branch 'openingbalances' of git://github.com/binnygopinath/mifosx into binnygopinath-openingbalances
Conflicts: mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryWritePlatformServiceJpaRepositoryImpl.java
This commit is contained in:
+9
@@ -173,4 +173,13 @@ public class GLAccountData {
|
||||
return this.glCode;
|
||||
}
|
||||
|
||||
public EnumOptionData getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public Integer getTypeId() {
|
||||
if (this.type != null) { return this.type.getId().intValue(); }
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+19
-2
@@ -24,6 +24,7 @@ import javax.ws.rs.core.UriInfo;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.mifosplatform.accounting.journalentry.data.JournalEntryAssociationParametersData;
|
||||
import org.mifosplatform.accounting.journalentry.data.JournalEntryData;
|
||||
import org.mifosplatform.accounting.journalentry.data.OfficeOpeningBalancesData;
|
||||
import org.mifosplatform.accounting.journalentry.service.JournalEntryReadPlatformService;
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||
@@ -53,7 +54,7 @@ public class JournalEntriesApiResource {
|
||||
private final String resourceNameForPermission = "JOURNALENTRY";
|
||||
|
||||
private final JournalEntryReadPlatformService journalEntryReadPlatformService;
|
||||
private final DefaultToApiJsonSerializer<JournalEntryData> apiJsonSerializerService;
|
||||
private final DefaultToApiJsonSerializer<Object> apiJsonSerializerService;
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
private final PlatformSecurityContext context;
|
||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||
@@ -61,7 +62,7 @@ public class JournalEntriesApiResource {
|
||||
@Autowired
|
||||
public JournalEntriesApiResource(final PlatformSecurityContext context,
|
||||
final JournalEntryReadPlatformService journalEntryReadPlatformService,
|
||||
final DefaultToApiJsonSerializer<JournalEntryData> toApiJsonSerializer,
|
||||
final DefaultToApiJsonSerializer<Object> toApiJsonSerializer,
|
||||
final ApiRequestParameterHelper apiRequestParameterHelper,
|
||||
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) {
|
||||
this.context = context;
|
||||
@@ -131,6 +132,10 @@ public class JournalEntriesApiResource {
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateRunningBalanceForJournalEntry()
|
||||
.withJson(jsonRequestBody).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "defineOpeningBalance")) {
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().defineOpeningBalanceForJournalEntry()
|
||||
.withJson(jsonRequestBody).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else {
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().createJournalEntry().withJson(jsonRequestBody).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
@@ -156,6 +161,18 @@ public class JournalEntriesApiResource {
|
||||
return this.apiJsonSerializerService.serialize(result);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Path("openingbalance")
|
||||
public String retrieveOpeningBalance(@Context final UriInfo uriInfo, @QueryParam("officeId") final Long officeId) {
|
||||
|
||||
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission);
|
||||
final OfficeOpeningBalancesData officeOpeningBalancesData = this.journalEntryReadPlatformService.retrieveOfficeOpeningBalances(officeId);
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.apiJsonSerializerService.serialize(settings, officeOpeningBalancesData);
|
||||
}
|
||||
|
||||
private boolean is(final String commandParam, final String commandValue) {
|
||||
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
|
||||
}
|
||||
|
||||
+38
@@ -8,6 +8,7 @@ package org.mifosplatform.accounting.journalentry.data;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.accounting.glaccount.data.GLAccountData;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
|
||||
@@ -99,6 +100,39 @@ public class JournalEntryData {
|
||||
this.currency = currency;
|
||||
}
|
||||
|
||||
public static JournalEntryData fromGLAccountData(final GLAccountData glAccountData) {
|
||||
|
||||
final Long id = null;
|
||||
final Long officeId = null;
|
||||
final String officeName = null;
|
||||
final String glAccountName = glAccountData.getName();
|
||||
final Long glAccountId = glAccountData.getId();
|
||||
final String glAccountCode = glAccountData.getGlCode();
|
||||
final EnumOptionData glAccountClassification = glAccountData.getType();
|
||||
final LocalDate transactionDate = null;
|
||||
final EnumOptionData entryType = null;
|
||||
final BigDecimal amount = null;
|
||||
final String transactionId = null;
|
||||
final Boolean manualEntry = null;
|
||||
final EnumOptionData entityType = null;
|
||||
final Long entityId = null;
|
||||
final Long createdByUserId = null;
|
||||
final LocalDate createdDate = null;
|
||||
final String createdByUserName = null;
|
||||
final String comments = null;
|
||||
final Boolean reversed = null;
|
||||
final String referenceNumber = null;
|
||||
final BigDecimal officeRunningBalance = null;
|
||||
final BigDecimal organizationRunningBalance = null;
|
||||
final Boolean runningBalanceComputed = null;
|
||||
final TransactionDetailData transactionDetailData = null;
|
||||
final CurrencyData currency = null;
|
||||
return new JournalEntryData(id, officeId, officeName, glAccountName, glAccountId, glAccountCode, glAccountClassification,
|
||||
transactionDate, entryType, amount, transactionId, manualEntry, entityType, entityId, createdByUserId, createdDate,
|
||||
createdByUserName, comments, reversed, referenceNumber, officeRunningBalance, organizationRunningBalance,
|
||||
runningBalanceComputed, transactionDetailData, currency);
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return this.id;
|
||||
}
|
||||
@@ -122,4 +156,8 @@ public class JournalEntryData {
|
||||
public Long getOfficeId() {
|
||||
return this.officeId;
|
||||
}
|
||||
|
||||
public String getTransactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package org.mifosplatform.accounting.journalentry.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.accounting.glaccount.data.GLAccountData;
|
||||
|
||||
public class OfficeOpeningBalancesData {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Long officeId;
|
||||
@SuppressWarnings("unused")
|
||||
private final String officeName;
|
||||
@SuppressWarnings("unused")
|
||||
private final LocalDate transactionDate;
|
||||
@SuppressWarnings("unused")
|
||||
private final GLAccountData contraAccount;
|
||||
@SuppressWarnings("unused")
|
||||
private final List<JournalEntryData> assetAccountOpeningBalances;
|
||||
@SuppressWarnings("unused")
|
||||
private final List<JournalEntryData> liabityAccountOpeningBalances;
|
||||
@SuppressWarnings("unused")
|
||||
private final List<JournalEntryData> incomeAccountOpeningBalances;
|
||||
@SuppressWarnings("unused")
|
||||
private final List<JournalEntryData> equityAccountOpeningBalances;
|
||||
@SuppressWarnings("unused")
|
||||
private final List<JournalEntryData> expenseAccountOpeningBalances;
|
||||
|
||||
private OfficeOpeningBalancesData(final Long officeId, final String officeName, final LocalDate transactionDate,
|
||||
final GLAccountData contraAccount, final List<JournalEntryData> assetAccountOpeningBalances,
|
||||
final List<JournalEntryData> liabityAccountOpeningBalances, final List<JournalEntryData> incomeAccountOpeningBalances,
|
||||
final List<JournalEntryData> equityAccountOpeningBalances, final List<JournalEntryData> expenseAccountOpeningBalances) {
|
||||
this.officeId = officeId;
|
||||
this.officeName = officeName;
|
||||
this.transactionDate = transactionDate;
|
||||
this.contraAccount = contraAccount;
|
||||
this.assetAccountOpeningBalances = assetAccountOpeningBalances;
|
||||
this.liabityAccountOpeningBalances = liabityAccountOpeningBalances;
|
||||
this.incomeAccountOpeningBalances = incomeAccountOpeningBalances;
|
||||
this.equityAccountOpeningBalances = equityAccountOpeningBalances;
|
||||
this.expenseAccountOpeningBalances = expenseAccountOpeningBalances;
|
||||
}
|
||||
|
||||
public static OfficeOpeningBalancesData createNew(final Long officeId, final String officeName, final LocalDate transactionDate,
|
||||
final GLAccountData contraAccount, final List<JournalEntryData> assetAccountOpeningBalances,
|
||||
final List<JournalEntryData> liabityAccountOpeningBalances, final List<JournalEntryData> incomeAccountOpeningBalances,
|
||||
final List<JournalEntryData> equityAccountOpeningBalances, final List<JournalEntryData> expenseAccountOpeningBalances) {
|
||||
return new OfficeOpeningBalancesData(officeId, officeName, transactionDate, contraAccount, assetAccountOpeningBalances,
|
||||
liabityAccountOpeningBalances, incomeAccountOpeningBalances, equityAccountOpeningBalances, expenseAccountOpeningBalances);
|
||||
}
|
||||
}
|
||||
+4
@@ -177,4 +177,8 @@ public class JournalEntry extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return this.paymentDetail;
|
||||
}
|
||||
|
||||
public String getTransactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
}
|
||||
+6
@@ -17,4 +17,10 @@ public interface JournalEntryRepository extends JpaRepository<JournalEntry, Long
|
||||
|
||||
@Query("from JournalEntry journalEntry where journalEntry.transactionId= :transactionId and journalEntry.reversed is false and journalEntry.manualEntry is true")
|
||||
List<JournalEntry> findUnReversedManualJournalEntriesByTransactionId(@Param("transactionId") String transactionId);
|
||||
|
||||
@Query("select DISTINCT j.transactionId from JournalEntry j where j.transactionId not in (select DISTINCT je.transactionId from JournalEntry je where je.glAccount.id = :contraId)")
|
||||
List<String> findNonContraTansactionIds(@Param("contraId") Long contraId);
|
||||
|
||||
@Query("select DISTINCT j.transactionId from JournalEntry j where j.office.id = :officeId and j.glAccount.id = :contraId and j.reversed is false and j.transactionId not in (select DISTINCT je.reversalJournalEntry.transactionId from JournalEntry je where je.reversed is true)")
|
||||
List<String> findNonReversedContraTansactionIds(@Param("contraId") Long contraId, @Param("officeId") Long officeId);
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package org.mifosplatform.accounting.journalentry.handler;
|
||||
|
||||
import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatformService;
|
||||
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 DefineOpeningBalanceCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final JournalEntryWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public DefineOpeningBalanceCommandHandler(final JournalEntryWritePlatformService writePlatformService) {
|
||||
this.writePlatformService = writePlatformService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(JsonCommand command) {
|
||||
return this.writePlatformService.defineOpeningBalance(command);
|
||||
}
|
||||
|
||||
}
|
||||
+3
@@ -9,6 +9,7 @@ import java.util.Date;
|
||||
|
||||
import org.mifosplatform.accounting.journalentry.data.JournalEntryAssociationParametersData;
|
||||
import org.mifosplatform.accounting.journalentry.data.JournalEntryData;
|
||||
import org.mifosplatform.accounting.journalentry.data.OfficeOpeningBalancesData;
|
||||
import org.mifosplatform.infrastructure.core.service.Page;
|
||||
import org.mifosplatform.infrastructure.core.service.SearchParameters;
|
||||
|
||||
@@ -19,4 +20,6 @@ public interface JournalEntryReadPlatformService {
|
||||
Page<JournalEntryData> retrieveAll(SearchParameters searchParameters, Long glAccountId, Boolean onlyManualEntries, Date fromDate,
|
||||
Date toDate, String transactionId, Integer entityType, JournalEntryAssociationParametersData associationParametersData);
|
||||
|
||||
OfficeOpeningBalancesData retrieveOfficeOpeningBalances(Long officeId);
|
||||
|
||||
}
|
||||
|
||||
+141
-1
@@ -10,24 +10,35 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.accounting.common.AccountingEnumerations;
|
||||
import org.mifosplatform.accounting.glaccount.data.GLAccountData;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccountType;
|
||||
import org.mifosplatform.accounting.glaccount.service.GLAccountReadPlatformService;
|
||||
import org.mifosplatform.accounting.journalentry.data.JournalEntryAssociationParametersData;
|
||||
import org.mifosplatform.accounting.journalentry.data.JournalEntryData;
|
||||
import org.mifosplatform.accounting.journalentry.data.OfficeOpeningBalancesData;
|
||||
import org.mifosplatform.accounting.journalentry.data.TransactionDetailData;
|
||||
import org.mifosplatform.accounting.journalentry.data.TransactionTypeEnumData;
|
||||
import org.mifosplatform.accounting.journalentry.exception.JournalEntriesNotFoundException;
|
||||
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
|
||||
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||
import org.mifosplatform.infrastructure.core.exception.GeneralPlatformDomainRuleException;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.infrastructure.core.service.Page;
|
||||
import org.mifosplatform.infrastructure.core.service.PaginationHelper;
|
||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.organisation.office.data.OfficeData;
|
||||
import org.mifosplatform.organisation.office.service.OfficeReadPlatformService;
|
||||
import org.mifosplatform.portfolio.account.PortfolioAccountType;
|
||||
import org.mifosplatform.infrastructure.core.service.SearchParameters;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
|
||||
@@ -41,17 +52,26 @@ import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@Service
|
||||
public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlatformService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
private final GLAccountReadPlatformService glAccountReadPlatformService;
|
||||
private final OfficeReadPlatformService officeReadPlatformService;
|
||||
|
||||
private final PaginationHelper<JournalEntryData> paginationHelper = new PaginationHelper<>();
|
||||
|
||||
@Autowired
|
||||
public JournalEntryReadPlatformServiceImpl(final RoutingDataSource dataSource) {
|
||||
public JournalEntryReadPlatformServiceImpl(final RoutingDataSource dataSource,
|
||||
final ConfigurationDomainService configurationDomainService, final GLAccountReadPlatformService glAccountReadPlatformService,
|
||||
final OfficeReadPlatformService officeReadPlatformService) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
this.glAccountReadPlatformService = glAccountReadPlatformService;
|
||||
this.officeReadPlatformService = officeReadPlatformService;
|
||||
}
|
||||
|
||||
private static final class GLJournalEntryMapper implements RowMapper<JournalEntryData> {
|
||||
@@ -333,4 +353,124 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public OfficeOpeningBalancesData retrieveOfficeOpeningBalances(final Long officeId) {
|
||||
|
||||
/**
|
||||
* Global configuration 'office-opening-balances-contra-account'
|
||||
* property value must not be null and it should be a equity account.
|
||||
*/
|
||||
final Long contraId = this.configurationDomainService.retrieveOpeningBalancesContraAccount();
|
||||
if (contraId == null) { throw new GeneralPlatformDomainRuleException(
|
||||
"error.msg.configuration.opening.balance.contra.account.cannot.be.null",
|
||||
"Configuration property 'office-opening-balances-contra-account' value can not be null",
|
||||
"office-opening-balances-contra-account"); }
|
||||
|
||||
final JournalEntryAssociationParametersData associationParametersData = new JournalEntryAssociationParametersData();
|
||||
final GLAccountData contraAccount = this.glAccountReadPlatformService.retrieveGLAccountById(contraId, associationParametersData);
|
||||
if (!GLAccountType.fromInt(contraAccount.getTypeId()).isEquityType()) { throw new GeneralPlatformDomainRuleException(
|
||||
"error.msg.configuration.opening.balance.contra.account.value.is.invalid.account.type",
|
||||
"Global configuration 'office-opening-balances-contra-account' value is not an equity type account", contraId); }
|
||||
|
||||
final OfficeData officeData = this.officeReadPlatformService.retrieveOffice(officeId);
|
||||
final List<JournalEntryData> allOpeningTransactions = populateAllTransactionsFromGLAccounts(contraId);
|
||||
final String contraTransactionId = retrieveContraAccountTransactionId(officeId, contraId);
|
||||
|
||||
List<JournalEntryData> existingOpeningBalanceTransactions = new ArrayList<>();
|
||||
if (StringUtils.isNotBlank(contraTransactionId)) {
|
||||
existingOpeningBalanceTransactions = retrieveOfficeBalanceTransactions(officeId, contraTransactionId);
|
||||
}
|
||||
final List<JournalEntryData> transactions = populateOpeningBalances(existingOpeningBalanceTransactions, allOpeningTransactions);
|
||||
final List<JournalEntryData> assetAccountOpeningBalances = new ArrayList<>();
|
||||
final List<JournalEntryData> liabityAccountOpeningBalances = new ArrayList<>();
|
||||
final List<JournalEntryData> incomeAccountOpeningBalances = new ArrayList<>();
|
||||
final List<JournalEntryData> equityAccountOpeningBalances = new ArrayList<>();
|
||||
final List<JournalEntryData> expenseAccountOpeningBalances = new ArrayList<>();
|
||||
|
||||
for (final JournalEntryData journalEntryData : transactions) {
|
||||
final GLAccountType type = GLAccountType.fromInt(journalEntryData.getGlAccountType().getId().intValue());
|
||||
if (type.isAssetType()) {
|
||||
assetAccountOpeningBalances.add(journalEntryData);
|
||||
} else if (type.isLiabilityType()) {
|
||||
liabityAccountOpeningBalances.add(journalEntryData);
|
||||
} else if (type.isEquityType()) {
|
||||
equityAccountOpeningBalances.add(journalEntryData);
|
||||
} else if (type.isIncomeType()) {
|
||||
incomeAccountOpeningBalances.add(journalEntryData);
|
||||
} else if (type.isExpenseType()) {
|
||||
expenseAccountOpeningBalances.add(journalEntryData);
|
||||
}
|
||||
}
|
||||
|
||||
final LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
|
||||
|
||||
final OfficeOpeningBalancesData officeOpeningBalancesData = OfficeOpeningBalancesData.createNew(officeId, officeData.name(),
|
||||
transactionDate, contraAccount, assetAccountOpeningBalances, liabityAccountOpeningBalances, incomeAccountOpeningBalances,
|
||||
equityAccountOpeningBalances, expenseAccountOpeningBalances);
|
||||
return officeOpeningBalancesData;
|
||||
}
|
||||
|
||||
private List<JournalEntryData> populateOpeningBalances(final List<JournalEntryData> existingOpeningBalanceTransactions,
|
||||
final List<JournalEntryData> allOpeningTransactions) {
|
||||
final List<JournalEntryData> allOpeningBalnceTransactions = new ArrayList<>(allOpeningTransactions.size());
|
||||
for (final JournalEntryData newOpeningBalanceTransaction : allOpeningTransactions) {
|
||||
boolean isNewTransactionAddedToCollection = false;
|
||||
for (final JournalEntryData existingOpeningBalanceTransaction : existingOpeningBalanceTransactions) {
|
||||
if (newOpeningBalanceTransaction.getGlAccountId().equals(existingOpeningBalanceTransaction.getGlAccountId())) {
|
||||
allOpeningBalnceTransactions.add(existingOpeningBalanceTransaction);
|
||||
isNewTransactionAddedToCollection = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isNewTransactionAddedToCollection) {
|
||||
allOpeningBalnceTransactions.add(newOpeningBalanceTransaction);
|
||||
}
|
||||
}
|
||||
return allOpeningBalnceTransactions;
|
||||
}
|
||||
|
||||
private List<JournalEntryData> populateAllTransactionsFromGLAccounts(final Long contraId) {
|
||||
final List<GLAccountData> glAccounts = this.glAccountReadPlatformService.retrieveAllEnabledDetailGLAccounts();
|
||||
final List<JournalEntryData> openingBalanceTransactions = new ArrayList<>(glAccounts.size());
|
||||
|
||||
for (final GLAccountData glAccountData : glAccounts) {
|
||||
if (!contraId.equals(glAccountData.getId())) {
|
||||
final JournalEntryData openingBalanceTransaction = JournalEntryData.fromGLAccountData(glAccountData);
|
||||
openingBalanceTransactions.add(openingBalanceTransaction);
|
||||
}
|
||||
}
|
||||
return openingBalanceTransactions;
|
||||
}
|
||||
|
||||
private List<JournalEntryData> retrieveOfficeBalanceTransactions(final Long officeId, final String transactionId) {
|
||||
final Long contraId = null;
|
||||
return retrieveContraTransactions(officeId, contraId, transactionId).getPageItems();
|
||||
}
|
||||
|
||||
private String retrieveContraAccountTransactionId(final Long officeId, final Long contraId) {
|
||||
final String transactionId = "";
|
||||
final Page<JournalEntryData> contraJournalEntries = retrieveContraTransactions(officeId, contraId, transactionId);
|
||||
if (!CollectionUtils.isEmpty(contraJournalEntries.getPageItems())) {
|
||||
final JournalEntryData contraTransaction = contraJournalEntries.getPageItems().get(contraJournalEntries.getPageItems().size()-1);
|
||||
return contraTransaction.getTransactionId();
|
||||
}
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
private Page<JournalEntryData> retrieveContraTransactions(final Long officeId, final Long contraId, final String transactionId) {
|
||||
final Integer offset = 0;
|
||||
final Integer limit = null;
|
||||
final String orderBy = "journalEntry.id";
|
||||
final String sortOrder = "ASC";
|
||||
final Integer entityType = null;
|
||||
final Boolean onlyManualEntries = null;
|
||||
final Date fromDate = null;
|
||||
final Date toDate = null;
|
||||
final JournalEntryAssociationParametersData associationParametersData = null;
|
||||
|
||||
final SearchParameters searchParameters = SearchParameters.forJournalEntries(officeId, offset, limit, orderBy, sortOrder);
|
||||
return retrieveAll(searchParameters, contraId, onlyManualEntries, fromDate, toDate, transactionId, entityType,
|
||||
associationParametersData);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -19,4 +19,7 @@ public interface JournalEntryWritePlatformService {
|
||||
void createJournalEntriesForLoan(Map<String, Object> accountingBridgeData);
|
||||
|
||||
void createJournalEntriesForSavings(Map<String, Object> accountingBridgeData);
|
||||
|
||||
CommandProcessingResult defineOpeningBalance(JsonCommand command);
|
||||
|
||||
}
|
||||
|
||||
+131
-5
@@ -19,6 +19,7 @@ import org.mifosplatform.accounting.closure.domain.GLClosureRepository;
|
||||
import org.mifosplatform.accounting.glaccount.data.GLAccountDataForLookup;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccount;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccountRepository;
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccountType;
|
||||
import org.mifosplatform.accounting.glaccount.exception.GLAccountNotFoundException;
|
||||
import org.mifosplatform.accounting.glaccount.service.GLAccountReadPlatformService;
|
||||
import org.mifosplatform.accounting.journalentry.api.JournalEntryJsonInputParams;
|
||||
@@ -36,11 +37,13 @@ import org.mifosplatform.accounting.journalentry.serialization.JournalEntryComma
|
||||
import org.mifosplatform.accounting.rule.domain.AccountingRule;
|
||||
import org.mifosplatform.accounting.rule.domain.AccountingRuleRepository;
|
||||
import org.mifosplatform.accounting.rule.exception.AccountingRuleNotFoundException;
|
||||
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.GeneralPlatformDomainRuleException;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
@@ -57,6 +60,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@Service
|
||||
public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements JournalEntryWritePlatformService {
|
||||
@@ -76,6 +80,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
private final OrganisationCurrencyRepositoryWrapper organisationCurrencyRepository;
|
||||
private final PlatformSecurityContext context;
|
||||
private final PaymentDetailWritePlatformService paymentDetailWritePlatformService;
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
|
||||
@Autowired
|
||||
public JournalEntryWritePlatformServiceJpaRepositoryImpl(final GLClosureRepository glClosureRepository,
|
||||
@@ -86,7 +91,8 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
final AccountingProcessorForSavingsFactory accountingProcessorForSavingsFactory,
|
||||
final GLAccountReadPlatformService glAccountReadPlatformService,
|
||||
final OrganisationCurrencyRepositoryWrapper organisationCurrencyRepository, final PlatformSecurityContext context,
|
||||
final PaymentDetailWritePlatformService paymentDetailWritePlatformService) {
|
||||
final PaymentDetailWritePlatformService paymentDetailWritePlatformService,
|
||||
final ConfigurationDomainService configurationDomainService) {
|
||||
this.glClosureRepository = glClosureRepository;
|
||||
this.officeRepository = officeRepository;
|
||||
this.glJournalEntryRepository = glJournalEntryRepository;
|
||||
@@ -100,6 +106,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
this.organisationCurrencyRepository = organisationCurrencyRepository;
|
||||
this.context = context;
|
||||
this.paymentDetailWritePlatformService = paymentDetailWritePlatformService;
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -277,12 +284,18 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
// is the transaction Id valid
|
||||
final List<JournalEntry> journalEntries = this.glJournalEntryRepository.findUnReversedManualJournalEntriesByTransactionId(command
|
||||
.getTransactionId());
|
||||
String reversalComment = command.stringValueOfParameterNamed("comments");
|
||||
|
||||
if (journalEntries.size() <= 1) { throw new JournalEntriesNotFoundException(command.getTransactionId()); }
|
||||
final String reversalTransactionId = revertJournalEntry(journalEntries, reversalComment);
|
||||
return new CommandProcessingResultBuilder().withTransactionId(reversalTransactionId).build();
|
||||
}
|
||||
|
||||
public String revertJournalEntry(final List<JournalEntry> journalEntries, String reversalComment) {
|
||||
final Long officeId = journalEntries.get(0).getOffice().getId();
|
||||
final String reversalTransactionId = generateTransactionId(officeId);
|
||||
final boolean manualEntry = true;
|
||||
String reversalComment = command.stringValueOfParameterNamed("comments");
|
||||
|
||||
final boolean useDefaultComment = StringUtils.isBlank(reversalComment);
|
||||
|
||||
validateCommentForReversal(reversalComment);
|
||||
@@ -290,8 +303,8 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
for (final JournalEntry journalEntry : journalEntries) {
|
||||
JournalEntry reversalJournalEntry;
|
||||
if (useDefaultComment) {
|
||||
reversalComment = "Reversal entry for Journal Entry with Entry Id :" + journalEntry.getId()
|
||||
+ " and transaction Id " + command.getTransactionId();
|
||||
reversalComment = "Reversal entry for Journal Entry with Entry Id :" + journalEntry.getId() + " and transaction Id "
|
||||
+ journalEntry.getTransactionId();
|
||||
}
|
||||
if (journalEntry.isDebitEntry()) {
|
||||
reversalJournalEntry = JournalEntry.createNew(journalEntry.getOffice(), journalEntry.getPaymentDetails(),
|
||||
@@ -311,7 +324,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
// save the updated journal entry
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
return new CommandProcessingResultBuilder().withTransactionId(reversalTransactionId).build();
|
||||
return reversalTransactionId;
|
||||
}
|
||||
|
||||
private void validateCommentForReversal(final String reversalComment) {
|
||||
@@ -430,4 +443,117 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
"Unknown data integrity issue with resource Journal Entry: " + realCause.getMessage());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult defineOpeningBalance(final JsonCommand command) {
|
||||
try {
|
||||
final JournalEntryCommand journalEntryCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json());
|
||||
journalEntryCommand.validateForCreate();
|
||||
|
||||
/**
|
||||
* Global configuration 'office-opening-balances-contra-account'
|
||||
* property value must not be null and it should be a equity
|
||||
* account.
|
||||
*/
|
||||
final Long contraId = this.configurationDomainService.retrieveOpeningBalancesContraAccount();
|
||||
if (contraId == null) { throw new GeneralPlatformDomainRuleException(
|
||||
"error.msg.configuration.opening.balance.contra.account.cannot.be.null",
|
||||
"Configuration property 'office-opening-balances-contra-account' value can not be null",
|
||||
"office-opening-balances-contra-account"); }
|
||||
|
||||
validateJournalEntriesArePostedBefore(contraId);
|
||||
|
||||
// check office is valid
|
||||
final Long officeId = command.longValueOfParameterNamed(JournalEntryJsonInputParams.OFFICE_ID.getValue());
|
||||
final Office office = this.officeRepository.findOne(officeId);
|
||||
if (office == null) { throw new OfficeNotFoundException(officeId); }
|
||||
|
||||
final String currencyCode = command.stringValueOfParameterNamed(JournalEntryJsonInputParams.CURRENCY_CODE.getValue());
|
||||
|
||||
validateBusinessRulesForJournalEntries(journalEntryCommand);
|
||||
|
||||
/**
|
||||
* revert old journal entries
|
||||
*/
|
||||
final List<String> transactionIdsToBeReversed = this.glJournalEntryRepository.findNonReversedContraTansactionIds(contraId,
|
||||
officeId);
|
||||
for (String transactionId : transactionIdsToBeReversed) {
|
||||
final List<JournalEntry> journalEntries = this.glJournalEntryRepository
|
||||
.findUnReversedManualJournalEntriesByTransactionId(transactionId);
|
||||
revertJournalEntry(journalEntries, "defining opening balance");
|
||||
}
|
||||
|
||||
/** Set a transaction Id and save these Journal entries **/
|
||||
final Date transactionDate = command.DateValueOfParameterNamed(JournalEntryJsonInputParams.TRANSACTION_DATE.getValue());
|
||||
final String transactionId = generateTransactionId(officeId);
|
||||
|
||||
saveAllDebitOrCreditOpeningBalanceEntries(journalEntryCommand, office, currencyCode, transactionDate,
|
||||
journalEntryCommand.getDebits(), transactionId, JournalEntryType.DEBIT, contraId);
|
||||
|
||||
saveAllDebitOrCreditOpeningBalanceEntries(journalEntryCommand, office, currencyCode, transactionDate,
|
||||
journalEntryCommand.getCredits(), transactionId, JournalEntryType.CREDIT, contraId);
|
||||
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withOfficeId(officeId)
|
||||
.withTransactionId(transactionId).build();
|
||||
} catch (final DataIntegrityViolationException dve) {
|
||||
handleJournalEntryDataIntegrityIssues(dve);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void saveAllDebitOrCreditOpeningBalanceEntries(final JournalEntryCommand command, final Office office,
|
||||
final String currencyCode, final Date transactionDate,
|
||||
final SingleDebitOrCreditEntryCommand[] singleDebitOrCreditEntryCommands, final String transactionId,
|
||||
final JournalEntryType type, final Long contraAccountId) {
|
||||
|
||||
final boolean manualEntry = true;
|
||||
final GLAccount contraAccount = this.glAccountRepository.findOne(contraAccountId);
|
||||
if (contraAccount == null) { throw new GLAccountNotFoundException(contraAccountId); }
|
||||
if (!GLAccountType.fromInt(contraAccount.getType()).isEquityType()) { throw new GeneralPlatformDomainRuleException(
|
||||
"error.msg.configuration.opening.balance.contra.account.value.is.invalid.account.type",
|
||||
"Global configuration 'office-opening-balances-contra-account' value is not an equity type account", contraAccountId); }
|
||||
validateGLAccountForTransaction(contraAccount);
|
||||
final JournalEntryType contraType = getContraType(type);
|
||||
String comments = command.getComments();
|
||||
|
||||
/** Validate current code is appropriate **/
|
||||
this.organisationCurrencyRepository.findOneWithNotFoundDetection(currencyCode);
|
||||
|
||||
for (final SingleDebitOrCreditEntryCommand singleDebitOrCreditEntryCommand : singleDebitOrCreditEntryCommands) {
|
||||
final GLAccount glAccount = this.glAccountRepository.findOne(singleDebitOrCreditEntryCommand.getGlAccountId());
|
||||
if (glAccount == null) { throw new GLAccountNotFoundException(singleDebitOrCreditEntryCommand.getGlAccountId()); }
|
||||
|
||||
validateGLAccountForTransaction(glAccount);
|
||||
|
||||
if (!StringUtils.isBlank(singleDebitOrCreditEntryCommand.getComments())) {
|
||||
comments = singleDebitOrCreditEntryCommand.getComments();
|
||||
}
|
||||
|
||||
final JournalEntry glJournalEntry = JournalEntry.createNew(office, null, glAccount, currencyCode, transactionId, manualEntry,
|
||||
transactionDate, type, singleDebitOrCreditEntryCommand.getAmount(), comments, null, null, null, null, null);
|
||||
this.glJournalEntryRepository.saveAndFlush(glJournalEntry);
|
||||
|
||||
final JournalEntry contraEntry = JournalEntry.createNew(office, null, contraAccount, currencyCode, transactionId, manualEntry,
|
||||
transactionDate, contraType, singleDebitOrCreditEntryCommand.getAmount(), comments, null, null, null, null, null);
|
||||
this.glJournalEntryRepository.saveAndFlush(contraEntry);
|
||||
}
|
||||
}
|
||||
|
||||
private JournalEntryType getContraType(final JournalEntryType type) {
|
||||
final JournalEntryType contraType;
|
||||
if (type.isCreditType()) {
|
||||
contraType = JournalEntryType.DEBIT;
|
||||
} else {
|
||||
contraType = JournalEntryType.CREDIT;
|
||||
}
|
||||
return contraType;
|
||||
}
|
||||
|
||||
private void validateJournalEntriesArePostedBefore(final Long contraId) {
|
||||
final List<String> transactionIds = this.glJournalEntryRepository.findNonContraTansactionIds(contraId);
|
||||
if (!CollectionUtils.isEmpty(transactionIds)) { throw new GeneralPlatformDomainRuleException(
|
||||
"error.msg.journalentry.defining.openingbalance.not.allowed",
|
||||
"Defining Opening balances not allowed after journal entries posted", transactionIds); }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -323,6 +323,14 @@ public class CommandWrapper {
|
||||
return this.actionName.equalsIgnoreCase("UPDATERUNNINGBALANCE") && this.entityName.equalsIgnoreCase("JOURNALENTRY");
|
||||
}
|
||||
|
||||
public boolean isDefineOpeningalance() {
|
||||
return this.actionName.equalsIgnoreCase("DEFINEOPENINGBALANCE") && this.entityName.equalsIgnoreCase("JOURNALENTRY");
|
||||
}
|
||||
|
||||
public boolean isUpdateOpeningbalance() {
|
||||
return this.actionName.equalsIgnoreCase("UPDATEOPENINGBALANCE") && this.entityName.equalsIgnoreCase("JOURNALENTRY");
|
||||
}
|
||||
|
||||
public boolean isFundResource() {
|
||||
return this.entityName.equalsIgnoreCase("FUND");
|
||||
}
|
||||
|
||||
+16
@@ -944,6 +944,22 @@ public class CommandWrapperBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder defineOpeningBalanceForJournalEntry() {
|
||||
this.actionName = "DEFINEOPENINGBALANCE";
|
||||
this.entityName = "JOURNALENTRY";
|
||||
this.entityId = null;
|
||||
this.href = "/journalentries/update";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder updateOpeningBalanceForJournalEntry() {
|
||||
this.actionName = "UPDATEOPENINGBALANCE";
|
||||
this.entityName = "JOURNALENTRY";
|
||||
this.entityId = null;
|
||||
this.href = "/journalentries/update";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder createSavingProduct() {
|
||||
this.actionName = "CREATE";
|
||||
this.entityName = "SAVINGSPRODUCT";
|
||||
|
||||
+2
@@ -472,6 +472,8 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
handler = this.applicationContext.getBean("reverseJournalEntryCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isUpdateRunningbalance()) {
|
||||
handler = this.applicationContext.getBean("updateRunningBalanceCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isDefineOpeningalance()) {
|
||||
handler = this.applicationContext.getBean("defineOpeningBalanceCommandHandler", NewCommandSourceHandler.class);
|
||||
} else {
|
||||
throw new UnsupportedCommandException(wrapper.commandName());
|
||||
}
|
||||
|
||||
+2
@@ -35,6 +35,8 @@ public interface ConfigurationDomainService {
|
||||
|
||||
Long retrieveGraceOnPenaltyPostingPeriod();
|
||||
|
||||
Long retrieveOpeningBalancesContraAccount();
|
||||
|
||||
boolean isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||
|
||||
Integer retrieveFinancialYearBeginningMonth();
|
||||
|
||||
+7
@@ -135,6 +135,13 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
|
||||
return property.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long retrieveOpeningBalancesContraAccount() {
|
||||
final String propertyName = "office-opening-balances-contra-account";
|
||||
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName);
|
||||
return property.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSavingsInterestPostingAtCurrentPeriodEnd() {
|
||||
final String propertyName = "savings-interest-posting-current-period-end";
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
INSERT INTO `m_code` (`code_name`,`is_system_defined`) VALUES('CenterClosureReason',1);
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
-- Example: INSERT INTO `acc_gl_account`
|
||||
-- (
|
||||
-- `name`, `parent_id`, `hierarchy`, `gl_code`, `disabled`, `manual_journal_entries_allowed`,
|
||||
-- `account_usage`, `classification_enum`, `tag_id`, `description`
|
||||
-- )
|
||||
-- VALUES
|
||||
-- (
|
||||
-- 'Opening Balances Contra Account', NULL, '.', 'OBCA', 0, 1,
|
||||
-- 1, 3, NULL, NULL
|
||||
-- );
|
||||
|
||||
INSERT INTO `c_configuration`
|
||||
(
|
||||
`name`,
|
||||
`value`,
|
||||
`enabled`
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
'office-opening-balances-contra-account',
|
||||
0, -- Or Example: (SELECT id FROM acc_gl_account WHERE gl_code = 'OBCA' ),
|
||||
1);
|
||||
|
||||
ALTER TABLE `c_configuration`
|
||||
ADD UNIQUE INDEX `name_UNIQUE` (`name`);
|
||||
|
||||
INSERT INTO `m_permission`
|
||||
(
|
||||
`grouping`, `code`, `entity_name`, `action_name`
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
'accounting', 'DEFINEOPENINGBALANCE_JOURNALENTRY', 'JOURNALENTRY', 'DEFINEOPENINGBALANCE'
|
||||
);
|
||||
Reference in New Issue
Block a user