Update Accounting Rule

Format Selected Options for UI

Add required database fields for Accounting rule

Cleanup Accounting Rule Update

Format outcoming json for accounting rule
This commit is contained in:
mifoscontributer
2013-06-06 18:42:00 +05:30
parent 06f2da8443
commit 5bff72fe87
20 changed files with 744 additions and 483 deletions
+144
View File
@@ -9494,6 +9494,30 @@ Content-Type: application/json
<tr>
<td class=fielddesc>Credit account for creating accounting rule</td>
</tr>
<tr class=alt>
<td>debitTags</td>
</tr>
<tr>
<td class=fielddesc>Debit tags for creating accounting rule, These tags fetches the all chart of accounts that are tagged with these tagIds</td>
</tr>
<tr class=alt>
<td>creditTags</td>
</tr>
<tr>
<td class=fielddesc>Credit tags for creating accounting rule, These tags fetches the all chart of accounts that are tagged with these tagIds</td>
</tr>
<tr class=alt>
<td>allowMultipleDebitEntries</td>
</tr>
<tr>
<td class=fielddesc>Allows to add multiple debits if the value is true, while creating journal entries with this rule</td>
</tr>
<tr class=alt>
<td>allowMultipleCreditEntries</td>
</tr>
<tr>
<td class=fielddesc>Allows to add multiple credits if the value is true, while creating journal entries with this rule</td>
</tr>
</table>
</div>
</div>
@@ -9605,6 +9629,64 @@ Request Body:
{
"officeId":1,
"resourceId":1
}
</code>
<code class="method-request">
POST accountingrules
Content-Type: application/json
Request Body:
{
"name": "fordocs",
"officeId": "1",
"debitTags": ["10","11"],
"allowMultipleDebitEntries": "true",
"creditTags": ["12","13"],
"allowMultipleCreditEntries": "true",
"description": "for api docs"
}
</code>
<code class="method-response">
{
"officeId":1,
"resourceId":2
}
</code>
<code class="method-request">
POST accountingrules
Content-Type: application/json
Request Body:
{
"name": "test123",
"officeId": "1",
"debitAccountHead": "21",
"creditTags": ["12", "13"],
"allowMultipleCreditEntries": "false",
"description": "Employee salary"
}
</code>
<code class="method-response">
{
"officeId":1,
"resourceId":3
}
</code>
<code class="method-request">
POST accountingrules
Content-Type: application/json
Request Body:
{
"name": "fordocstest",
"officeId": "1",
"debitTags": ["10", "11"],
"allowMultipleDebitEntries": "false",
"creditAccountHead": "9",
"description": "for api docs"
}
</code>
<code class="method-response">
{
"officeId":1,
"resourceId":4
}
</code>
</div>
@@ -14890,6 +14972,68 @@ Request Body:
{
"officeId":1,
"transactionId":"RS9MCISID4WK1ZM"
}
</code>
<code class="method-declaration">
POST https://DomainName/api/v1/journalentries
</code>
<code class="method-request">
POST journalentries
Content-Type: application/json
Request Body:
{
"locale": "en",
"dateFormat": "dd MMMM yyyy",
"officeId": "1",
"transactionDate": "23 May 2013",
"referenceNumber": "547",
"comments": "asdf",
"accountingRule": "2",
"credits":[{"glAccountId":1,
"amount":5000},
{"glAccountId":2,
"amount":5000}
],
"debits":[{"glAccountId":3,
"amount":5000},
{"glAccountId":4,
"amount":5000}
]
}
</code>
<code class="method-response">
{
"officeId":1,
"transactionId":"RS9MCISID4WK1ZM"
}
</code>
<code class="method-declaration">
POST https://DomainName/api/v1/journalentries
</code>
<code class="method-request">
POST journalentries
Content-Type: application/json
Request Body:
{
"locale": "en",
"dateFormat": "dd MMMM yyyy",
"officeId": "1",
"transactionDate": "23 May 2013",
"referenceNumber": "547",
"comments": "asdf",
"accountingRule": "3",
"credits":[{"glAccountId":1,
"amount":5000},
{"glAccountId":2,
"amount":5000}
],
"amount": "10000"
}
</code>
<code class="method-response">
{
"officeId":1,
"transactionId":"RS9MCISID4WK1ZM"
}
</code>
</div>
@@ -0,0 +1,6 @@
ALTER TABLE `acc_accounting_rule`
ADD COLUMN `allow_multiple_debits` TINYINT(1) NOT NULL DEFAULT '0' AFTER `debit_account_id`,
ADD COLUMN `allow_multiple_credits` TINYINT(1) NOT NULL DEFAULT '0' AFTER `credit_account_id`;
ALTER TABLE acc_rule_tags
ADD UNIQUE KEY `UNIQUE_ACCOUNT_RULE_TAGS` (`acc_rule_id`,`tag_id`,`acc_type_enum`);
@@ -48,10 +48,6 @@ public class GLAccountData {
final Collection<CodeValueData> allowedIncomeTagOptions;
final Collection<CodeValueData> allowedExpensesTagOptions;
// for predefined journal entry template
private final List<GLAccountDataForLookup> creditAccounts;
private final List<GLAccountDataForLookup> debitAccounts;
public GLAccountData(final Long id, final String name, final Long parentId, final String glCode, final boolean disabled,
final boolean manualEntriesAllowed, final EnumOptionData type, final EnumOptionData usage, final String description,
final String nameDecorated, final CodeValueData tagId) {
@@ -78,8 +74,6 @@ public class GLAccountData {
this.allowedEquityTagOptions = null;
this.allowedIncomeTagOptions = null;
this.allowedExpensesTagOptions = null;
this.creditAccounts = null;
this.debitAccounts = null;
}
public GLAccountData(final GLAccountData accountData, final List<EnumOptionData> accountTypeOptions,
@@ -112,8 +106,6 @@ public class GLAccountData {
this.allowedEquityTagOptions = allowedEquityTagOptions;
this.allowedIncomeTagOptions = allowedIncomeTagOptions;
this.allowedExpensesTagOptions = allowedExpensesTagOptions;
this.creditAccounts = accountData.creditAccounts;
this.debitAccounts = accountData.debitAccounts;
}
public static GLAccountData sensibleDefaultsForNewGLAccountCreation(final Integer glAccType) {
@@ -160,8 +152,6 @@ public class GLAccountData {
this.allowedEquityTagOptions = null;
this.allowedIncomeTagOptions = null;
this.allowedExpensesTagOptions = null;
this.creditAccounts = null;
this.debitAccounts = null;
}
public Long getId() {
@@ -73,7 +73,7 @@ public class JournalEntry extends AbstractAuditableCustom<AppUser, Long> {
@SuppressWarnings("unused")
@Column(name = "entity_id")
private Long entityId;
@Column(name = "ref_num")
private String referenceNumber;
@@ -104,7 +104,7 @@ public class JournalEntry extends AbstractAuditableCustom<AppUser, Long> {
this.entityType = entityType;
this.entityId = entityId;
this.referenceNumber = referenceNumber;
}
public boolean isDebitEntry() {
@@ -139,8 +139,8 @@ public class JournalEntry extends AbstractAuditableCustom<AppUser, Long> {
this.reversed = reversed;
}
public String getReferenceNumber() {
return this.referenceNumber;
}
public String getReferenceNumber() {
return this.referenceNumber;
}
}
@@ -45,4 +45,12 @@ public enum JournalEntryType {
return name().toString();
}
public boolean isDebitType() {
return this.value.equals(JournalEntryType.DEBIT.getValue());
}
public boolean isCreditType() {
return this.value.equals(JournalEntryType.CREDIT.getValue());
}
}
@@ -5,10 +5,13 @@
*/
package org.mifosplatform.accounting.rule.api;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.Consumes;
@@ -19,7 +22,6 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
@@ -28,12 +30,14 @@ import org.mifosplatform.accounting.common.AccountingConstants;
import org.mifosplatform.accounting.glaccount.data.GLAccountData;
import org.mifosplatform.accounting.glaccount.service.GLAccountReadPlatformService;
import org.mifosplatform.accounting.rule.data.AccountingRuleData;
import org.mifosplatform.accounting.rule.data.AccountingTagRuleData;
import org.mifosplatform.accounting.rule.service.AccountingRuleReadPlatformService;
import org.mifosplatform.commands.domain.CommandWrapper;
import org.mifosplatform.commands.service.CommandWrapperBuilder;
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
import org.mifosplatform.infrastructure.codes.service.CodeValueReadPlatformService;
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
@@ -51,9 +55,9 @@ import org.springframework.stereotype.Component;
public class AccountingRuleApiResource {
private static final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "officeId", "officeName",
"accountToDebitId", "accountToCreditId", "name", "description", "systemDefined", "allowedAssetsTagOptions",
"allowedLiabilitiesTagOptions", "allowedEquityTagOptions", "allowedIncomeTagOptions", "allowedExpensesTagOptions", "debitTags",
"creditTags", "creditAccounts", "debitAccounts"));
"accountToDebitId", "accountToCreditId", "name", "description", "systemDefined", "allowedCreditTagOptions",
"allowedDebitTagOptions", "debitTags", "creditTags", "creditAccounts", "debitAccounts", "allowMultipleCreditEntries",
"allowMultipleDebitEntries", "tag"));
private final String resourceNameForPermission = "ACCOUNTINGRULE";
@@ -101,10 +105,19 @@ public class AccountingRuleApiResource {
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAllAccountingRules(@Context final UriInfo uriInfo, @QueryParam("officeId") final Long officeId) {
public String retrieveAllAccountingRules(@Context final UriInfo uriInfo) {
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission);
final List<AccountingRuleData> accountingRuleDatas = this.accountingRuleReadPlatformService.retrieveAllAccountingRules(officeId);
final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
final Long officeId = this.context.authenticatedUser().getOffice().getId();
boolean isAssociationParametersExists = false;
if (!associationParameters.isEmpty()) {
if (associationParameters.contains("all")) {
isAssociationParametersExists = true; // If true, retrieve additional fields for journal entry form.
}
}
final List<AccountingRuleData> accountingRuleDatas = this.accountingRuleReadPlatformService.retrieveAllAccountingRules(officeId,
isAssociationParametersExists);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.apiJsonSerializerService.serialize(settings, accountingRuleDatas, RESPONSE_DATA_PARAMETERS);
@@ -117,7 +130,6 @@ public class AccountingRuleApiResource {
public String retreiveAccountingRule(@PathParam("accountingRuleId") final Long accountingRuleId, @Context final UriInfo uriInfo) {
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
AccountingRuleData accountingRuleData = this.accountingRuleReadPlatformService.retrieveAccountingRuleById(accountingRuleId);
@@ -166,30 +178,47 @@ public class AccountingRuleApiResource {
return this.apiJsonSerializerService.serialize(result);
}
private AccountingRuleData handleTemplate(final AccountingRuleData accountingRuleData) {
private AccountingRuleData handleTemplate(AccountingRuleData accountingRuleData) {
final List<GLAccountData> allowedAccounts = this.accountReadPlatformService.retrieveAllEnabledDetailGLAccounts();
final List<OfficeData> allowedOffices = (List<OfficeData>) this.officeReadPlatformService.retrieveAllOfficesForDropdown();
final Collection<CodeValueData> allowedAssetsTagOptions = defaultIfEmpty(this.codeValueReadPlatformService
.retrieveCodeValuesByCode(AccountingConstants.ASSESTS_TAG_OPTION_CODE_NAME));
final Collection<CodeValueData> allowedLiabilitiesTagOptions = defaultIfEmpty(this.codeValueReadPlatformService
.retrieveCodeValuesByCode(AccountingConstants.LIABILITIES_TAG_OPTION_CODE_NAME));
final Collection<CodeValueData> allowedEquityTagOptions = defaultIfEmpty(this.codeValueReadPlatformService
.retrieveCodeValuesByCode(AccountingConstants.EQUITY_TAG_OPTION_CODE_NAME));
final Collection<CodeValueData> allowedIncomeTagOptions = defaultIfEmpty(this.codeValueReadPlatformService
.retrieveCodeValuesByCode(AccountingConstants.INCOME_TAG_OPTION_CODE_NAME));
final Collection<CodeValueData> allowedExpensesTagOptions = defaultIfEmpty(this.codeValueReadPlatformService
.retrieveCodeValuesByCode(AccountingConstants.EXPENSES_TAG_OPTION_CODE_NAME));
if (accountingRuleData == null) { return new AccountingRuleData(allowedAccounts, allowedOffices, allowedAssetsTagOptions,
allowedLiabilitiesTagOptions, allowedEquityTagOptions, allowedIncomeTagOptions, allowedExpensesTagOptions); }
return new AccountingRuleData(accountingRuleData, allowedAccounts, allowedOffices, allowedAssetsTagOptions,
allowedLiabilitiesTagOptions, allowedEquityTagOptions, allowedIncomeTagOptions, allowedExpensesTagOptions);
final Collection<CodeValueData> allowedTagOptions = this.codeValueReadPlatformService
.retrieveCodeValuesByCode(AccountingConstants.ASSESTS_TAG_OPTION_CODE_NAME);
allowedTagOptions.addAll(this.codeValueReadPlatformService.retrieveCodeValuesByCode(AccountingConstants.LIABILITIES_TAG_OPTION_CODE_NAME));
allowedTagOptions.addAll(this.codeValueReadPlatformService.retrieveCodeValuesByCode(AccountingConstants.EQUITY_TAG_OPTION_CODE_NAME));
allowedTagOptions.addAll(this.codeValueReadPlatformService.retrieveCodeValuesByCode(AccountingConstants.INCOME_TAG_OPTION_CODE_NAME));
allowedTagOptions.addAll(this.codeValueReadPlatformService.retrieveCodeValuesByCode(AccountingConstants.EXPENSES_TAG_OPTION_CODE_NAME));
if (accountingRuleData == null) {
final Collection<CodeValueData> allowedCreditTagOptions = allowedTagOptions;
final Collection<CodeValueData> allowedDebitTagOptions = allowedTagOptions;
accountingRuleData = new AccountingRuleData(allowedAccounts, allowedOffices, allowedCreditTagOptions, allowedDebitTagOptions);
} else {
final Collection<CodeValueData> allowedCreditTagOptions = retrieveSelectedTags(allowedTagOptions, accountingRuleData.getCreditTags());
final Collection<CodeValueData> allowedDebitTagOptions = retrieveSelectedTags(allowedTagOptions, accountingRuleData.getDebitTags());
accountingRuleData = new AccountingRuleData(accountingRuleData, allowedAccounts, allowedOffices, allowedCreditTagOptions,
allowedDebitTagOptions);
}
return accountingRuleData;
}
private Collection<CodeValueData> defaultIfEmpty(final Collection<CodeValueData> collection) {
Collection<CodeValueData> returnCollection = null;
if (collection != null && !collection.isEmpty()) {
returnCollection = collection;
private Collection<CodeValueData> retrieveSelectedTags(final Collection<CodeValueData> allowedTagOptions,
final List<AccountingTagRuleData> existedTags) {
final Collection<CodeValueData> tempOptions = new ArrayList<CodeValueData>(allowedTagOptions);
final Map<Long, CodeValueData> selectedTags = new HashMap<Long, CodeValueData>();
for (final AccountingTagRuleData accountingTagRuleData : existedTags) {
for (final CodeValueData codeValueData : tempOptions) {
if (codeValueData.getId().equals(accountingTagRuleData.getTag().getId())) {
selectedTags.put(codeValueData.getId(), codeValueData);
}
}
}
return returnCollection;
tempOptions.removeAll(selectedTags.values());
return tempOptions;
}
}
@@ -13,7 +13,8 @@ import java.util.Set;
***/
public enum AccountingRuleJsonInputParams {
ID("id"), OFFICE_ID("officeId"), ACCOUNT_TO_DEBIT("debitAccountHead"), ACCOUNT_TO_CREDIT("creditAccountHead"), NAME("name"), DESCRIPTION(
"description"), SYSTEM_DEFINED("systemDefined"), DEBIT_ACCOUNT_TAGS("debitTags"), CREDIT_ACCOUNT_TAGS("creditTags");
"description"), SYSTEM_DEFINED("systemDefined"), DEBIT_ACCOUNT_TAGS("debitTags"), CREDIT_ACCOUNT_TAGS("creditTags"), ALLOW_MULTIPLE_CREDIT_ENTRIES(
"allowMultipleCreditEntries"), ALLOW_MULTIPLE_DEBIT_ENTRIES("allowMultipleDebitEntries");
private final String value;
@@ -1,79 +0,0 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.accounting.rule.command;
import java.util.ArrayList;
import java.util.List;
import org.mifosplatform.accounting.rule.api.AccountingRuleJsonInputParams;
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
/**
* Immutable command for adding an accounting closure
*/
public class AccountingRuleCommand {
@SuppressWarnings("unused")
private final Long id;
private final Long officeId;
private final Long accountToDebitId;
private final Long accountToCreditId;
private final String name;
private final String description;
public AccountingRuleCommand(Long id, Long officeId, Long accountToDebitId, Long accountToCreditId, String name, String description) {
this.id = id;
this.officeId = officeId;
this.accountToDebitId = accountToDebitId;
this.accountToCreditId = accountToCreditId;
this.name = name;
this.description = description;
}
public void validateForCreate() {
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("AccountingRule");
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue()).value(this.accountToDebitId)
.notNull().integerGreaterThanZero();
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue()).value(this.accountToCreditId)
.notNull().integerGreaterThanZero();
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.OFFICE_ID.getValue()).value(this.officeId).ignoreIfNull()
.integerGreaterThanZero();
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.NAME.getValue()).value(this.name).notBlank()
.notExceedingLengthOf(100);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.DESCRIPTION.getValue()).value(this.description).ignoreIfNull()
.notExceedingLengthOf(500);
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
public void validateForUpdate() {
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("AccountingRule");
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue()).value(this.accountToDebitId)
.ignoreIfNull().notBlank().integerGreaterThanZero();
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue()).value(this.accountToCreditId)
.ignoreIfNull().notBlank().integerGreaterThanZero();
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.OFFICE_ID.getValue()).value(this.officeId).ignoreIfNull()
.integerGreaterThanZero();
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.NAME.getValue()).value(this.name).ignoreIfNull().notBlank()
.notExceedingLengthOf(100);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.DESCRIPTION.getValue()).value(this.description).ignoreIfNull()
.notExceedingLengthOf(500);
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
}
@@ -28,6 +28,8 @@ public class AccountingRuleData {
private final String name;
private final String description;
private final boolean systemDefined;
private final boolean allowMultipleDebitEntries;
private final boolean allowMultipleCreditEntries;
private final GLAccountData debitAccountHead;
private final GLAccountData creditAccountHead;
private final List<AccountingTagRuleData> creditTags;
@@ -36,33 +38,28 @@ public class AccountingRuleData {
// template
private List<OfficeData> allowedOffices = new ArrayList<OfficeData>();
private List<GLAccountData> allowedAccounts = new ArrayList<GLAccountData>();
private final Collection<CodeValueData> allowedAssetsTagOptions;
private final Collection<CodeValueData> allowedLiabilitiesTagOptions;
private final Collection<CodeValueData> allowedEquityTagOptions;
private final Collection<CodeValueData> allowedIncomeTagOptions;
private final Collection<CodeValueData> allowedExpensesTagOptions;
private final Collection<CodeValueData> allowedCreditTagOptions;
private final Collection<CodeValueData> allowedDebitTagOptions;
private final List<GLAccountDataForLookup> creditAccounts;
private final List<GLAccountDataForLookup> debitAccounts;
public AccountingRuleData(final AccountingRuleData accountingRuleData, final List<GLAccountData> allowedAccounts,
final List<OfficeData> allowedOffices, final Collection<CodeValueData> allowedAssetsTagOptions,
final Collection<CodeValueData> allowedLiabilitiesTagOptions, final Collection<CodeValueData> allowedEquityTagOptions,
final Collection<CodeValueData> allowedIncomeTagOptions, final Collection<CodeValueData> allowedExpensesTagOptions) {
final List<OfficeData> allowedOffices, final Collection<CodeValueData> allowedCreditTagOptions,
final Collection<CodeValueData> allowedDebitTagOptions) {
this.id = accountingRuleData.id;
this.officeId = accountingRuleData.officeId;
this.officeName = accountingRuleData.officeName;
this.name = accountingRuleData.name;
this.description = accountingRuleData.description;
this.systemDefined = accountingRuleData.systemDefined;
this.allowMultipleDebitEntries = accountingRuleData.allowMultipleDebitEntries;
this.allowMultipleCreditEntries = accountingRuleData.allowMultipleCreditEntries;
this.allowedOffices = allowedOffices;
this.allowedAccounts = allowedAccounts;
this.debitAccountHead = accountingRuleData.debitAccountHead;
this.creditAccountHead = accountingRuleData.creditAccountHead;
this.allowedAssetsTagOptions = allowedAssetsTagOptions;
this.allowedLiabilitiesTagOptions = allowedLiabilitiesTagOptions;
this.allowedEquityTagOptions = allowedEquityTagOptions;
this.allowedIncomeTagOptions = allowedIncomeTagOptions;
this.allowedExpensesTagOptions = allowedExpensesTagOptions;
this.allowedCreditTagOptions = allowedCreditTagOptions;
this.allowedDebitTagOptions = allowedDebitTagOptions;
this.creditTags = accountingRuleData.creditTags;
this.debitTags = accountingRuleData.debitTags;
this.creditAccounts = accountingRuleData.creditAccounts;
@@ -70,24 +67,21 @@ public class AccountingRuleData {
}
public AccountingRuleData(final List<GLAccountData> allowedAccounts, final List<OfficeData> allowedOffices,
final Collection<CodeValueData> allowedAssetsTagOptions, final Collection<CodeValueData> allowedLiabilitiesTagOptions,
final Collection<CodeValueData> allowedEquityTagOptions, final Collection<CodeValueData> allowedIncomeTagOptions,
final Collection<CodeValueData> allowedExpensesTagOptions) {
final Collection<CodeValueData> allowedCreditTagOptions, final Collection<CodeValueData> allowedDebitTagOptions) {
this.id = null;
this.officeId = null;
this.officeName = null;
this.name = null;
this.description = null;
this.systemDefined = false;
this.allowMultipleDebitEntries = false;
this.allowMultipleCreditEntries = false;
this.allowedOffices = allowedOffices;
this.allowedAccounts = allowedAccounts;
this.debitAccountHead = null;
this.creditAccountHead = null;
this.allowedAssetsTagOptions = allowedAssetsTagOptions;
this.allowedLiabilitiesTagOptions = allowedLiabilitiesTagOptions;
this.allowedEquityTagOptions = allowedEquityTagOptions;
this.allowedIncomeTagOptions = allowedIncomeTagOptions;
this.allowedExpensesTagOptions = allowedExpensesTagOptions;
this.allowedCreditTagOptions = allowedCreditTagOptions;
this.allowedDebitTagOptions = allowedDebitTagOptions;
this.creditTags = null;
this.debitTags = null;
this.creditAccounts = null;
@@ -95,22 +89,22 @@ public class AccountingRuleData {
}
public AccountingRuleData(final Long id, final Long officeId, final String officeName, final String name, final String description,
final boolean systemDefined, final GLAccountData debitAccountData, final GLAccountData creditAccountData) {
final boolean systemDefined, final boolean allowMultipleDebitEntries, final boolean allowMultipleCreditEntries,
final GLAccountData debitAccountData, final GLAccountData creditAccountData) {
this.id = id;
this.officeId = officeId;
this.officeName = officeName;
this.name = name;
this.description = description;
this.systemDefined = systemDefined;
this.allowMultipleDebitEntries = allowMultipleDebitEntries;
this.allowMultipleCreditEntries = allowMultipleCreditEntries;
this.allowedOffices = null;
this.allowedAccounts = null;
this.debitAccountHead = debitAccountData;
this.creditAccountHead = creditAccountData;
this.allowedAssetsTagOptions = null;
this.allowedLiabilitiesTagOptions = null;
this.allowedEquityTagOptions = null;
this.allowedIncomeTagOptions = null;
this.allowedExpensesTagOptions = null;
this.allowedCreditTagOptions = null;
this.allowedDebitTagOptions = null;
this.creditTags = null;
this.debitTags = null;
this.creditAccounts = new ArrayList<GLAccountDataForLookup>();
@@ -126,15 +120,14 @@ public class AccountingRuleData {
this.name = accountingRuleData.name;
this.description = accountingRuleData.description;
this.systemDefined = accountingRuleData.systemDefined;
this.allowMultipleDebitEntries = accountingRuleData.allowMultipleDebitEntries;
this.allowMultipleCreditEntries = accountingRuleData.allowMultipleCreditEntries;
this.allowedOffices = accountingRuleData.allowedOffices;
this.allowedAccounts = accountingRuleData.allowedAccounts;
this.debitAccountHead = accountingRuleData.debitAccountHead;
this.creditAccountHead = accountingRuleData.creditAccountHead;
this.allowedAssetsTagOptions = accountingRuleData.allowedAssetsTagOptions;
this.allowedLiabilitiesTagOptions = accountingRuleData.allowedLiabilitiesTagOptions;
this.allowedEquityTagOptions = accountingRuleData.allowedEquityTagOptions;
this.allowedIncomeTagOptions = accountingRuleData.allowedIncomeTagOptions;
this.allowedExpensesTagOptions = accountingRuleData.allowedExpensesTagOptions;
this.allowedCreditTagOptions = accountingRuleData.allowedCreditTagOptions;
this.allowedDebitTagOptions = accountingRuleData.allowedDebitTagOptions;
this.creditTags = creditTags;
this.creditAccounts = creditAccounts;
this.debitTags = debitTags;
@@ -5,21 +5,25 @@
*/
package org.mifosplatform.accounting.rule.data;
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
public class AccountingTagRuleData {
@SuppressWarnings("unused")
private final Long id;
@SuppressWarnings("unused")
private final Long tagId;
private final CodeValueData tag;
@SuppressWarnings("unused")
private final EnumOptionData transactionType;
public AccountingTagRuleData(final Long id, final Long tagId, final EnumOptionData transactionType) {
public AccountingTagRuleData(final Long id, final CodeValueData tag, final EnumOptionData transactionType) {
this.id = id;
this.tagId = tagId;
this.tag = tag;
this.transactionType = transactionType;
}
public CodeValueData getTag() {
return tag;
}
}
@@ -6,9 +6,11 @@
package org.mifosplatform.accounting.rule.domain;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
@@ -23,6 +25,7 @@ import org.apache.commons.lang.StringUtils;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.mifosplatform.accounting.glaccount.domain.GLAccount;
import org.mifosplatform.accounting.journalentry.domain.JournalEntryType;
import org.mifosplatform.accounting.rule.api.AccountingRuleJsonInputParams;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.organisation.office.domain.Office;
@@ -52,16 +55,22 @@ public class AccountingRule extends AbstractPersistable<Long> {
@Column(name = "system_defined", nullable = false)
private Boolean systemDefined;
@LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "accountingRule", orphanRemoval = true)
private List<AccountingTagRule> accountingTagRules = new ArrayList<AccountingTagRule>();
private final List<AccountingTagRule> accountingTagRules = new ArrayList<AccountingTagRule>();
@Column(name = "allow_multiple_credits", nullable = false)
private boolean allowMultipleCreditEntries;
@Column(name = "allow_multiple_debits", nullable = false)
private boolean allowMultipleDebitEntries;
protected AccountingRule() {}
private AccountingRule(Office office, GLAccount accountToDebit, GLAccount accountToCredit, String name, String description,
boolean systemDefined) {
private AccountingRule(final Office office, final GLAccount accountToDebit, final GLAccount accountToCredit, final String name,
final String description, final boolean systemDefined, final boolean allowMultipleCreditEntries,
final boolean allowMultipleDebitEntries) {
this.accountToDebit = accountToDebit;
this.accountToCredit = accountToCredit;
this.name = name;
@@ -71,24 +80,34 @@ public class AccountingRule extends AbstractPersistable<Long> {
this.description = this.description.trim();
}
this.systemDefined = systemDefined;
this.allowMultipleCreditEntries = allowMultipleCreditEntries;
this.allowMultipleDebitEntries = allowMultipleDebitEntries;
}
public static AccountingRule fromJson(final Office office, final GLAccount accountToDebit, final GLAccount accountToCredit,
JsonCommand command) {
final JsonCommand command, final boolean allowMultipleCreditEntries, final boolean allowMultipleDebitEntries) {
final String name = command.stringValueOfParameterNamed(AccountingRuleJsonInputParams.NAME.getValue());
final String description = command.stringValueOfParameterNamed(AccountingRuleJsonInputParams.DESCRIPTION.getValue());
final boolean systemDefined = false;
return new AccountingRule(office, accountToDebit, accountToCredit, name, description, systemDefined);
return new AccountingRule(office, accountToDebit, accountToCredit, name, description, systemDefined, allowMultipleCreditEntries,
allowMultipleDebitEntries);
}
public Map<String, Object> update(final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(5);
handlePropertyUpdate(command, actualChanges, AccountingRuleJsonInputParams.OFFICE_ID.getValue(), 0L);
handlePropertyUpdate(command, actualChanges, AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue(), 0L);
handlePropertyUpdate(command, actualChanges, AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue(), 0L);
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(10);
handlePropertyUpdate(command, actualChanges, AccountingRuleJsonInputParams.OFFICE_ID.getValue(), this.office == null ? 0L
: this.office.getId());
handlePropertyUpdate(command, actualChanges, AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue(),
this.accountToDebit == null ? 0L : this.accountToDebit.getId());
handlePropertyUpdate(command, actualChanges, AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue(),
this.accountToCredit == null ? 0L : this.accountToCredit.getId());
handlePropertyUpdate(command, actualChanges, AccountingRuleJsonInputParams.NAME.getValue(), this.name);
handlePropertyUpdate(command, actualChanges, AccountingRuleJsonInputParams.DESCRIPTION.getValue(), this.description);
handlePropertyUpdate(command, actualChanges, AccountingRuleJsonInputParams.SYSTEM_DEFINED.getValue(), this.systemDefined);
handlePropertyUpdate(command, actualChanges, AccountingRuleJsonInputParams.ALLOW_MULTIPLE_CREDIT_ENTRIES.getValue(),
this.allowMultipleCreditEntries);
handlePropertyUpdate(command, actualChanges, AccountingRuleJsonInputParams.ALLOW_MULTIPLE_DEBIT_ENTRIES.getValue(),
this.allowMultipleDebitEntries);
return actualChanges;
}
@@ -114,6 +133,14 @@ public class AccountingRule extends AbstractPersistable<Long> {
// now update actual property
if (paramName.equals(AccountingRuleJsonInputParams.SYSTEM_DEFINED.getValue())) {
this.systemDefined = newValue;
} else if (paramName.equals(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_CREDIT_ENTRIES.getValue())) {
if (this.accountToCredit == null) {
this.allowMultipleCreditEntries = newValue;
}
} else if (paramName.equals(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_DEBIT_ENTRIES.getValue())) {
if (this.accountToDebit == null) {
this.allowMultipleDebitEntries = newValue;
}
}
}
}
@@ -134,7 +161,7 @@ public class AccountingRule extends AbstractPersistable<Long> {
}
}
public void setOffice(Office office) {
public void setOffice(final Office office) {
this.office = office;
}
@@ -150,11 +177,11 @@ public class AccountingRule extends AbstractPersistable<Long> {
return this.accountToCredit;
}
public void setAccountToDebit(GLAccount accountToDebit) {
public void setAccountToDebit(final GLAccount accountToDebit) {
this.accountToDebit = accountToDebit;
}
public void setAccountToCredit(GLAccount accountToCredit) {
public void setAccountToCredit(final GLAccount accountToCredit) {
this.accountToCredit = accountToCredit;
}
@@ -162,12 +189,66 @@ public class AccountingRule extends AbstractPersistable<Long> {
return this.description;
}
public List<AccountingTagRule> updateAccountingRuleForTags(List<AccountingTagRule> debitAccountingTagRules) {
for(AccountingTagRule accountingTagRule : debitAccountingTagRules){
accountingTagRule.updateAccountingTagRule(this);
this.accountingTagRules.add(accountingTagRule);
}
return debitAccountingTagRules;
}
public List<AccountingTagRule> getAccountingTagRules() {
return this.accountingTagRules;
}
public void updateAccountingRuleForTags(final List<AccountingTagRule> debitAccountingTagRules) {
for (final AccountingTagRule accountingTagRule : debitAccountingTagRules) {
accountingTagRule.updateAccountingTagRule(this);
this.accountingTagRules.add(accountingTagRule);
}
}
public void updateDebitAccount(final GLAccount accountToDebit) {
this.accountToDebit = accountToDebit;
this.allowMultipleDebitEntries = false;
}
public void updateCreditAccount(final GLAccount accountToCredit) {
this.accountToCredit = accountToCredit;
this.allowMultipleCreditEntries = false;
}
public void updateAllowMultipleCreditEntries(final boolean allowMultipleCreditEntries) {
this.allowMultipleCreditEntries = allowMultipleCreditEntries;
}
public void updateAllowMultipleDebitEntries(final boolean allowMultipleDebitEntries) {
this.allowMultipleDebitEntries = allowMultipleDebitEntries;
}
public void updateTags(final JournalEntryType type) {
final Set<AccountingTagRule> existedCreditTags = new HashSet<AccountingTagRule>();
final Set<AccountingTagRule> existedDebitTags = new HashSet<AccountingTagRule>();
for (final AccountingTagRule accountingTagRule : this.accountingTagRules) {
if (accountingTagRule.isCreditAccount()) {
existedCreditTags.add(accountingTagRule);
} else if (accountingTagRule.isDebitAccount()) {
existedDebitTags.add(accountingTagRule);
}
}
if (type.isCreditType()) {
this.accountingTagRules.retainAll(existedCreditTags);
} else if (type.isDebitType()) {
this.accountingTagRules.retainAll(existedDebitTags);
}
}
public Set<AccountingTagRule> getAccountingTagRulesByType(final JournalEntryType type) {
final Set<AccountingTagRule> existedTags = new HashSet<AccountingTagRule>();
for (final AccountingTagRule accountingTagRule : this.accountingTagRules) {
if (accountingTagRule.getAccountType().equals(type.getValue())) {
existedTags.add(accountingTagRule);
}
}
return existedTags;
}
public void removeOldTags(final List<AccountingTagRule> accountsToRemove) {
this.accountingTagRules.removeAll(accountsToRemove);
}
}
@@ -10,20 +10,20 @@ import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import org.mifosplatform.accounting.journalentry.domain.JournalEntryType;
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity
@Table(name = "acc_rule_tags")
@Table(name = "acc_rule_tags", uniqueConstraints = { @UniqueConstraint(columnNames = { "acc_rule_id", "tag_id", "acc_type_enum" }, name = "UNIQUE_ACCOUNT_RULE_TAGS") })
public class AccountingTagRule extends AbstractPersistable<Long> {
@SuppressWarnings("unused")
@ManyToOne
@JoinColumn(name = "acc_rule_id", nullable = false)
private AccountingRule accountingRule;
@SuppressWarnings("unused")
@ManyToOne
@JoinColumn(name = "tag_id", nullable = false)
private CodeValue tagId;
@@ -52,4 +52,16 @@ public class AccountingTagRule extends AbstractPersistable<Long> {
return this.accountType;
}
public boolean isDebitAccount() {
return JournalEntryType.fromInt(this.accountType).isDebitType();
}
public boolean isCreditAccount() {
return JournalEntryType.fromInt(this.accountType).isCreditType();
}
public Long getTagId() {
return this.tagId.getId();
}
}
@@ -0,0 +1,12 @@
package org.mifosplatform.accounting.rule.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class AccountingRuleDataException extends AbstractPlatformDomainRuleException {
public AccountingRuleDataException(final String debitOrCreditAccount, final String debitOrCreditTags) {
super("error.msg.accounting.rule." + debitOrCreditAccount + ".or." + debitOrCreditTags + ".required", debitOrCreditAccount + " or "
+ debitOrCreditTags + " required", debitOrCreditAccount, debitOrCreditTags);
}
}
@@ -16,5 +16,9 @@ public class AccountingRuleDuplicateException extends AbstractPlatformDomainRule
public AccountingRuleDuplicateException(String name) {
super("error.msg.accounting.rule.duplicate", "An accounting rule with the name " + name + " already exists" + name);
}
public AccountingRuleDuplicateException() {
super("error.msg.accounting.rule.tag.duplicate", "The accounting rule already have the tags which you defined");
}
}
@@ -6,55 +6,182 @@
package org.mifosplatform.accounting.rule.serialization;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.accounting.rule.api.AccountingRuleJsonInputParams;
import org.mifosplatform.accounting.rule.command.AccountingRuleCommand;
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer;
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 org.springframework.util.ObjectUtils;
import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken;
@Component
public final class AccountingRuleCommandFromApiJsonDeserializer extends AbstractFromApiJsonDeserializer<AccountingRuleCommand> {
public class AccountingRuleCommandFromApiJsonDeserializer {
/**
* The parameters supported for this command.
*/
private final Set<String> supportedParameters = AccountingRuleJsonInputParams.getAllValues();
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public AccountingRuleCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonfromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonfromApiJsonHelper;
public AccountingRuleCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
@Override
public AccountingRuleCommand commandFromApiJson(final String json) {
public void validateForCreate(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
final Set<String> supportedParameters = AccountingRuleJsonInputParams.getAllValues();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("AccountingRule");
final JsonElement element = this.fromApiJsonHelper.parse(json);
final Long id = this.fromApiJsonHelper.extractLongNamed(AccountingRuleJsonInputParams.ID.getValue(), element);
final Long officeId = this.fromApiJsonHelper.extractLongNamed(AccountingRuleJsonInputParams.OFFICE_ID.getValue(), element);
final Long accountToDebitId = this.fromApiJsonHelper.extractLongNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue(),
element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue()).value(accountToDebitId)
.ignoreIfNull().integerGreaterThanZero();
final Long accountToCreditId = this.fromApiJsonHelper.extractLongNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue(),
element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue()).value(accountToCreditId)
.ignoreIfNull().integerGreaterThanZero();
final Long officeId = this.fromApiJsonHelper.extractLongNamed(AccountingRuleJsonInputParams.OFFICE_ID.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.OFFICE_ID.getValue()).value(officeId).ignoreIfNull()
.integerGreaterThanZero();
final String name = this.fromApiJsonHelper.extractStringNamed(AccountingRuleJsonInputParams.NAME.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.NAME.getValue()).value(name).notBlank().notExceedingLengthOf(100);
final String description = this.fromApiJsonHelper.extractStringNamed(AccountingRuleJsonInputParams.DESCRIPTION.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.DESCRIPTION.getValue()).value(description).ignoreIfNull()
.notExceedingLengthOf(500);
final String[] creditTags = this.fromApiJsonHelper.extractArrayNamed(AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue(),
element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue()).value(creditTags).ignoreIfNull()
.arrayNotEmpty();
validateCreditOrDebitTagArray(creditTags, baseDataValidator, AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue());
final String[] debitTags = this.fromApiJsonHelper.extractArrayNamed(AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue(),
element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue()).value(debitTags).ignoreIfNull()
.arrayNotEmpty();
validateCreditOrDebitTagArray(debitTags, baseDataValidator, AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue());
final String allowMultipleCredits = this.fromApiJsonHelper.extractStringNamed(
AccountingRuleJsonInputParams.ALLOW_MULTIPLE_CREDIT_ENTRIES.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_CREDIT_ENTRIES.getValue())
.value(allowMultipleCredits).ignoreIfNull().notBlank();
final Boolean allowMultipleCreditEntries = this.fromApiJsonHelper.extractBooleanNamed(
AccountingRuleJsonInputParams.ALLOW_MULTIPLE_CREDIT_ENTRIES.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_CREDIT_ENTRIES.getValue())
.value(allowMultipleCreditEntries).ignoreIfNull();
final String allowMultipleDebits = this.fromApiJsonHelper.extractStringNamed(
AccountingRuleJsonInputParams.ALLOW_MULTIPLE_DEBIT_ENTRIES.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_DEBIT_ENTRIES.getValue())
.value(allowMultipleDebits).ignoreIfNull().notBlank();
final Boolean allowMultipleDebitEntries = this.fromApiJsonHelper.extractBooleanNamed(
AccountingRuleJsonInputParams.ALLOW_MULTIPLE_DEBIT_ENTRIES.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_DEBIT_ENTRIES.getValue())
.value(allowMultipleDebitEntries).ignoreIfNull();
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
public void validateCreditOrDebitTagArray(final String[] creditOrDebitTagArray, final DataValidatorBuilder baseDataValidator,
final String parameter) {
if (creditOrDebitTagArray != null && !ObjectUtils.isEmpty(creditOrDebitTagArray)) {
for (final String tag : creditOrDebitTagArray) {
baseDataValidator.reset().parameter(parameter).value(tag).ignoreIfNull().notBlank().longGreaterThanZero();
}
}
}
public void validateForUpdate(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("AccountingRule");
final JsonElement element = this.fromApiJsonHelper.parse(json);
final Long accountToDebitId = this.fromApiJsonHelper.extractLongNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue(),
element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue()).value(accountToDebitId)
.ignoreIfNull().notBlank().integerGreaterThanZero();
final Long accountToCreditId = this.fromApiJsonHelper.extractLongNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue(),
element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue()).value(accountToCreditId)
.ignoreIfNull().notBlank().integerGreaterThanZero();
final Long officeId = this.fromApiJsonHelper.extractLongNamed(AccountingRuleJsonInputParams.OFFICE_ID.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.OFFICE_ID.getValue()).value(officeId).ignoreIfNull()
.integerGreaterThanZero();
final String name = this.fromApiJsonHelper.extractStringNamed(AccountingRuleJsonInputParams.NAME.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.NAME.getValue()).value(name).ignoreIfNull().notBlank()
.notExceedingLengthOf(100);
final String description = this.fromApiJsonHelper.extractStringNamed(AccountingRuleJsonInputParams.DESCRIPTION.getValue(), element);
// final String[] creditTags =
this.fromApiJsonHelper.extractArrayNamed(AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue(), element);
// final String[] debitTags =
this.fromApiJsonHelper.extractArrayNamed(AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.DESCRIPTION.getValue()).value(description).ignoreIfNull()
.notExceedingLengthOf(500);
return new AccountingRuleCommand(id, officeId, accountToDebitId, accountToCreditId, name, description);
final String[] creditTags = this.fromApiJsonHelper.extractArrayNamed(AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue(),
element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue()).value(creditTags).ignoreIfNull()
.arrayNotEmpty();
validateCreditOrDebitTagArray(creditTags, baseDataValidator, AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue());
final String[] debitTags = this.fromApiJsonHelper.extractArrayNamed(AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue(),
element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue()).value(debitTags).ignoreIfNull()
.arrayNotEmpty();
validateCreditOrDebitTagArray(debitTags, baseDataValidator, AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue());
final String allowMultipleCredits = this.fromApiJsonHelper.extractStringNamed(
AccountingRuleJsonInputParams.ALLOW_MULTIPLE_CREDIT_ENTRIES.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_CREDIT_ENTRIES.getValue())
.value(allowMultipleCredits).ignoreIfNull().notBlank();
final Boolean allowMultipleCreditEntries = this.fromApiJsonHelper.extractBooleanNamed(
AccountingRuleJsonInputParams.ALLOW_MULTIPLE_CREDIT_ENTRIES.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_CREDIT_ENTRIES.getValue())
.value(allowMultipleCreditEntries).ignoreIfNull();
final String allowMultipleDebits = this.fromApiJsonHelper.extractStringNamed(
AccountingRuleJsonInputParams.ALLOW_MULTIPLE_DEBIT_ENTRIES.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_DEBIT_ENTRIES.getValue())
.value(allowMultipleDebits).ignoreIfNull().notBlank();
final Boolean allowMultipleDebitEntries = this.fromApiJsonHelper.extractBooleanNamed(
AccountingRuleJsonInputParams.ALLOW_MULTIPLE_DEBIT_ENTRIES.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_DEBIT_ENTRIES.getValue())
.value(allowMultipleDebitEntries).ignoreIfNull();
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
}
}
@@ -1,152 +0,0 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.accounting.rule.service;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.accounting.rule.api.AccountingRuleJsonInputParams;
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
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 org.springframework.util.ObjectUtils;
import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken;
@Component
public class AccountingRuleDataValidator {
/**
* The parameters supported for this command.
*/
private final Set<String> supportedParameters = AccountingRuleJsonInputParams.getAllValues();
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public AccountingRuleDataValidator(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
public void validateForCreate(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("AccountingRule");
final JsonElement element = this.fromApiJsonHelper.parse(json);
final Long accountToDebitId = this.fromApiJsonHelper.extractLongNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue(),
element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue()).value(accountToDebitId)
.ignoreIfNull().integerGreaterThanZero();
final Long accountToCreditId = this.fromApiJsonHelper.extractLongNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue(),
element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue()).value(accountToCreditId)
.ignoreIfNull().integerGreaterThanZero();
final Long officeId = this.fromApiJsonHelper.extractLongNamed(AccountingRuleJsonInputParams.OFFICE_ID.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.OFFICE_ID.getValue()).value(officeId).ignoreIfNull()
.integerGreaterThanZero();
final String name = this.fromApiJsonHelper.extractStringNamed(AccountingRuleJsonInputParams.NAME.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.NAME.getValue()).value(name).notBlank().notExceedingLengthOf(100);
final String description = this.fromApiJsonHelper.extractStringNamed(AccountingRuleJsonInputParams.DESCRIPTION.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.DESCRIPTION.getValue()).value(description).ignoreIfNull()
.notExceedingLengthOf(500);
final String[] creditTags = this.fromApiJsonHelper.extractArrayNamed(AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue(),
element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue()).value(creditTags).ignoreIfNull()
.arrayNotEmpty();
validateCreditOrDebitTagArray(creditTags, baseDataValidator, AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue());
final String[] debitTags = this.fromApiJsonHelper.extractArrayNamed(AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue(),
element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue()).value(debitTags).ignoreIfNull()
.arrayNotEmpty();
validateCreditOrDebitTagArray(debitTags, baseDataValidator, AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue());
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
public void validateCreditOrDebitTagArray(final String[] creditOrDebitTagArray, final DataValidatorBuilder baseDataValidator,
final String parameter) {
if (creditOrDebitTagArray != null && !ObjectUtils.isEmpty(creditOrDebitTagArray)) {
for (final String tag : creditOrDebitTagArray) {
baseDataValidator.reset().parameter(parameter).value(tag).ignoreIfNull().notBlank().longGreaterThanZero();
}
}
}
public void validateForUpdate(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("AccountingRule");
final JsonElement element = this.fromApiJsonHelper.parse(json);
final Long accountToDebitId = this.fromApiJsonHelper.extractLongNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue(),
element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue()).value(accountToDebitId)
.ignoreIfNull().notBlank().integerGreaterThanZero();
final Long accountToCreditId = this.fromApiJsonHelper.extractLongNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue(),
element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue()).value(accountToCreditId)
.ignoreIfNull().notBlank().integerGreaterThanZero();
final Long officeId = this.fromApiJsonHelper.extractLongNamed(AccountingRuleJsonInputParams.OFFICE_ID.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.OFFICE_ID.getValue()).value(officeId).ignoreIfNull()
.integerGreaterThanZero();
final String name = this.fromApiJsonHelper.extractStringNamed(AccountingRuleJsonInputParams.NAME.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.NAME.getValue()).value(name).ignoreIfNull().notBlank()
.notExceedingLengthOf(100);
final String description = this.fromApiJsonHelper.extractStringNamed(AccountingRuleJsonInputParams.DESCRIPTION.getValue(), element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.DESCRIPTION.getValue()).value(description).ignoreIfNull()
.notExceedingLengthOf(500);
final String[] creditTags = this.fromApiJsonHelper.extractArrayNamed(AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue(),
element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue()).value(creditTags).ignoreIfNull()
.arrayNotEmpty();
validateCreditOrDebitTagArray(creditTags, baseDataValidator, AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue());
final String[] debitTags = this.fromApiJsonHelper.extractArrayNamed(AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue(),
element);
baseDataValidator.reset().parameter(AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue()).value(debitTags).ignoreIfNull()
.arrayNotEmpty();
validateCreditOrDebitTagArray(debitTags, baseDataValidator, AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue());
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
}
@@ -11,7 +11,7 @@ import org.mifosplatform.accounting.rule.data.AccountingRuleData;
public interface AccountingRuleReadPlatformService {
List<AccountingRuleData> retrieveAllAccountingRules(Long OfficeId);
List<AccountingRuleData> retrieveAllAccountingRules(Long OfficeId, boolean isAssociationParametersExists);
AccountingRuleData retrieveAccountingRuleById(Long accountingRuleId);
@@ -20,6 +20,7 @@ import org.mifosplatform.accounting.journalentry.domain.JournalEntryType;
import org.mifosplatform.accounting.rule.data.AccountingRuleData;
import org.mifosplatform.accounting.rule.data.AccountingTagRuleData;
import org.mifosplatform.accounting.rule.exception.AccountingRuleNotFoundException;
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
@@ -44,68 +45,22 @@ public class AccountingRuleReadPlatformServiceImpl implements AccountingRuleRead
this.glAccountReadPlatformService = glAccountReadPlatformService;
}
// Will remove the old one if everything goes well.
/* private static final class AccountingRuleMapper implements RowMapper<AccountingRuleData> {
private final String schemaSql;
public AccountingRuleMapper() {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder
.append("distinct rule.id as id,rule.name as name, rule.office_id as officeId,office.name as officeName,")
.append(" rule.debit_account_id as debitAccountId,rule.credit_account_id as creditAccountId,")
.append(" rule.description as description, rule.system_defined as systemDefined, ")
.append("debitAccount.glName as debitAccountName, debitAccount.glCode as debitAccountGLCode,")
.append("creditAccount.glName as creditAccountName, creditAccount.glCode as creditAccountGLCode ")
.append("from (Select gl.id as id,gl.name as glName, gl.gl_code as glCode from acc_gl_account gl,acc_accounting_rule rule ")
.append("where gl.id=rule.debit_account_id ) as debitAccount,")
.append("(Select gl.id as id,gl.name as glName, gl.gl_code as glCode from acc_gl_account gl,acc_accounting_rule rule ")
.append("where gl.id=rule.credit_account_id ) as creditAccount,")
.append("acc_accounting_rule rule left join m_office office on rule.office_id=office.id ")
.append("where debitAccount.id=rule.debit_account_id and creditAccount.id = rule.credit_account_id");
this.schemaSql = sqlBuilder.toString();
}
public String schema() {
return this.schemaSql;
}
@Override
public AccountingRuleData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final Long officeId = JdbcSupport.getLong(rs, "officeId");
final String officeName = rs.getString("officeName");
final String name = rs.getString("name");
final String description = rs.getString("description");
final Long accountToDebitId = rs.getLong("debitAccountId");
final Long accountToCreditId = rs.getLong("creditAccountId");
final boolean systemDefined = rs.getBoolean("systemDefined");
final String debitAccountName = rs.getString("debitAccountName");
final String creditAccountName = rs.getString("creditAccountName");
final String debitAccountGLCode = rs.getString("debitAccountGLCode");
final String creditAccountGLCode = rs.getString("creditAccountGLCode");
final GLAccountData debitAccountData = new GLAccountData(accountToDebitId, debitAccountName, debitAccountGLCode);
final GLAccountData creditAccountData = new GLAccountData(accountToCreditId, creditAccountName, creditAccountGLCode);
return new AccountingRuleData(id, officeId, officeName, name, description, systemDefined, debitAccountData, creditAccountData);
}
}*/
private static final class AccountingRuleDataExtractor implements ResultSetExtractor<Map<Long, AccountingRuleData>> {
private final String schemaSql;
private final JdbcTemplate jdbcTemplate;
private final GLAccountReadPlatformService glAccountReadPlatformService;
private final boolean isAssociationParametersExists;
public AccountingRuleDataExtractor(final JdbcTemplate jdbcTemplate, final GLAccountReadPlatformService glAccountReadPlatformService) {
public AccountingRuleDataExtractor(final JdbcTemplate jdbcTemplate,
final GLAccountReadPlatformService glAccountReadPlatformService, final boolean isAssociationParametersExists) {
this.jdbcTemplate = jdbcTemplate;
this.glAccountReadPlatformService = glAccountReadPlatformService;
this.isAssociationParametersExists = isAssociationParametersExists;
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder
.append(" rule.id as id,rule.name as name, rule.office_id as officeId,office.name as officeName,")
.append(" rule.description as description, rule.system_defined as systemDefined, ")
.append(" rule.description as description, rule.system_defined as systemDefined, rule.allow_multiple_debits as allowMultipleDebitEntries, rule.allow_multiple_credits as allowMultipleCreditEntries, ")
.append("debitAccount.id AS debitAccountId, debitAccount.name as debitAccountName, debitAccount.gl_code as debitAccountGLCode, ")
.append("creditAccount.id AS creditAccountId, creditAccount.name as creditAccountName, creditAccount.gl_code as creditAccountGLCode")
.append(" from m_office AS office, acc_accounting_rule AS rule ")
@@ -134,6 +89,8 @@ public class AccountingRuleReadPlatformServiceImpl implements AccountingRuleRead
final Long accountToDebitId = JdbcSupport.getLong(rs, "debitAccountId");
final Long accountToCreditId = JdbcSupport.getLong(rs, "creditAccountId");
final boolean systemDefined = rs.getBoolean("systemDefined");
final boolean allowMultipleDebitEntries = rs.getBoolean("allowMultipleDebitEntries");
final boolean allowMultipleCreditEntries = rs.getBoolean("allowMultipleCreditEntries");
final String debitAccountName = rs.getString("debitAccountName");
final String creditAccountName = rs.getString("creditAccountName");
final String debitAccountGLCode = rs.getString("debitAccountGLCode");
@@ -144,19 +101,21 @@ public class AccountingRuleReadPlatformServiceImpl implements AccountingRuleRead
final GLAccountData creditAccountData = accountToCreditId == null ? null : new GLAccountData(accountToCreditId,
creditAccountName, creditAccountGLCode);
accountingRuleData = new AccountingRuleData(id, officeId, officeName, name, description, systemDefined,
debitAccountData, creditAccountData);
allowMultipleDebitEntries, allowMultipleCreditEntries, debitAccountData, creditAccountData);
}
if (accountingRuleData.getCreditAccountHead() == null) {
final List<AccountingTagRuleData> creditTags = getCreditOrDebitTags(id, JournalEntryType.CREDIT.getValue());
final List<GLAccountDataForLookup> creditAccounts = this.glAccountReadPlatformService.retrieveAccountsByTagId(id,
JournalEntryType.CREDIT.getValue());
final List<AccountingTagRuleData> creditTags = !this.isAssociationParametersExists ? getCreditOrDebitTags(id,
JournalEntryType.CREDIT.getValue()) : null;
final List<GLAccountDataForLookup> creditAccounts = this.isAssociationParametersExists ? this.glAccountReadPlatformService
.retrieveAccountsByTagId(id, JournalEntryType.CREDIT.getValue()) : null;
accountingRuleData = new AccountingRuleData(accountingRuleData, creditTags, creditAccounts,
accountingRuleData.getDebitTags(), accountingRuleData.getDebitAccounts());
}
if (accountingRuleData.getDebitAccountHead() == null) {
final List<AccountingTagRuleData> debitTags = getCreditOrDebitTags(id, JournalEntryType.DEBIT.getValue());
final List<GLAccountDataForLookup> debitAccounts = this.glAccountReadPlatformService.retrieveAccountsByTagId(id,
JournalEntryType.DEBIT.getValue());
final List<AccountingTagRuleData> debitTags = !this.isAssociationParametersExists ? getCreditOrDebitTags(id,
JournalEntryType.DEBIT.getValue()) : null;
final List<GLAccountDataForLookup> debitAccounts = this.isAssociationParametersExists ? this.glAccountReadPlatformService
.retrieveAccountsByTagId(id, JournalEntryType.DEBIT.getValue()) : null;
accountingRuleData = new AccountingRuleData(accountingRuleData, accountingRuleData.getCreditTags(),
accountingRuleData.getCreditAccounts(), debitTags, debitAccounts);
}
@@ -174,9 +133,9 @@ public class AccountingRuleReadPlatformServiceImpl implements AccountingRuleRead
}
@Override
public List<AccountingRuleData> retrieveAllAccountingRules(final Long officeId) {
public List<AccountingRuleData> retrieveAllAccountingRules(final Long officeId, final boolean isAssociationParametersExists) {
final AccountingRuleDataExtractor resultSetExtractor = new AccountingRuleDataExtractor(this.jdbcTemplate,
this.glAccountReadPlatformService);
this.glAccountReadPlatformService, isAssociationParametersExists);
Object[] arguments = new Object[] {};
String sql = "select " + resultSetExtractor.schema() + " and system_defined=0 ";
if (officeId != null) {
@@ -192,7 +151,7 @@ public class AccountingRuleReadPlatformServiceImpl implements AccountingRuleRead
public AccountingRuleData retrieveAccountingRuleById(final Long accountingRuleId) {
try {
final AccountingRuleDataExtractor resultSetExtractor = new AccountingRuleDataExtractor(this.jdbcTemplate,
this.glAccountReadPlatformService);
this.glAccountReadPlatformService, false);
final String sql = "select " + resultSetExtractor.schema() + " and rule.id = ?";
final Map<Long, AccountingRuleData> extractedData = this.jdbcTemplate.query(sql, resultSetExtractor,
@@ -208,7 +167,7 @@ public class AccountingRuleReadPlatformServiceImpl implements AccountingRuleRead
private static final class AccountingTagRuleDataMapper implements RowMapper<AccountingTagRuleData> {
public String taggedAccountSchema() {
return " tag.id as id,tag.tag_id as tagId, tag.acc_type_enum as transactionType from acc_rule_tags tag "
return " tag.id as id,tag.tag_id as tagId, tag.acc_type_enum as transactionType, cv.code_value as tagName from m_code_value cv join acc_rule_tags tag on tag.tag_id=cv.id "
+ "join acc_accounting_rule rule on tag.acc_rule_id=rule.id ";
}
@@ -217,8 +176,10 @@ public class AccountingRuleReadPlatformServiceImpl implements AccountingRuleRead
final Long id = rs.getLong("id");
final Long tagId = rs.getLong("tagId");
final Integer transactionType = JdbcSupport.getInteger(rs, "transactionType");
final String tagName = rs.getString("tagName");
final CodeValueData tag = CodeValueData.instance(tagId, tagName);
final EnumOptionData transactionTypeEnum = AccountingEnumerations.journalEntryType(transactionType);
return new AccountingTagRuleData(id, tagId, transactionTypeEnum);
return new AccountingTagRuleData(id, tag, transactionTypeEnum);
}
}
@@ -6,9 +6,14 @@
package org.mifosplatform.accounting.rule.service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.accounting.closure.api.GLClosureJsonInputParams;
import org.mifosplatform.accounting.glaccount.domain.GLAccount;
import org.mifosplatform.accounting.glaccount.domain.GLAccountRepositoryWrapper;
@@ -18,7 +23,9 @@ import org.mifosplatform.accounting.rule.domain.AccountingRule;
import org.mifosplatform.accounting.rule.domain.AccountingRuleRepository;
import org.mifosplatform.accounting.rule.domain.AccountingRuleRepositoryWrapper;
import org.mifosplatform.accounting.rule.domain.AccountingTagRule;
import org.mifosplatform.accounting.rule.exception.AccountingRuleDataException;
import org.mifosplatform.accounting.rule.exception.AccountingRuleDuplicateException;
import org.mifosplatform.accounting.rule.serialization.AccountingRuleCommandFromApiJsonDeserializer;
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.mifosplatform.infrastructure.codes.domain.CodeValueRepository;
import org.mifosplatform.infrastructure.codes.exception.CodeValueNotFoundException;
@@ -45,13 +52,13 @@ public class AccountingRuleWritePlatformServiceJpaRepositoryImpl implements Acco
private final AccountingRuleRepository accountingRuleRepository;
private final GLAccountRepositoryWrapper accountRepositoryWrapper;
private final OfficeRepository officeRepository;
private final AccountingRuleDataValidator fromApiJsonDeserializer;
private final AccountingRuleCommandFromApiJsonDeserializer fromApiJsonDeserializer;
private final CodeValueRepository codeValueRepository;
@Autowired
public AccountingRuleWritePlatformServiceJpaRepositoryImpl(final AccountingRuleRepositoryWrapper accountingRuleRepositoryWrapper,
final GLAccountRepositoryWrapper accountRepositoryWrapper, final OfficeRepository officeRepository,
final AccountingRuleRepository ruleRepository, final AccountingRuleDataValidator fromApiJsonDeserializer,
final AccountingRuleRepository ruleRepository, final AccountingRuleCommandFromApiJsonDeserializer fromApiJsonDeserializer,
final CodeValueRepository codeValueRepository) {
this.accountRepositoryWrapper = accountRepositoryWrapper;
this.officeRepository = officeRepository;
@@ -67,8 +74,9 @@ public class AccountingRuleWritePlatformServiceJpaRepositoryImpl implements Acco
*/
private void handleAccountingRuleIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) {
final Throwable realCause = dve.getMostSpecificCause();
if (realCause.getMessage().contains("accounting_rule_name_unique")) { throw new AccountingRuleDuplicateException(
command.stringValueOfParameterNamed(AccountingRuleJsonInputParams.NAME.getValue())); }
if (realCause.getMessage().contains("accounting_rule_name_unique")) {
throw new AccountingRuleDuplicateException(command.stringValueOfParameterNamed(AccountingRuleJsonInputParams.NAME.getValue()));
} else if (realCause.getMessage().contains("UNIQUE_ACCOUNT_RULE_TAGS")) { throw new AccountingRuleDuplicateException(); }
logger.error(dve.getMessage(), dve);
throw new PlatformDataIntegrityException("error.msg.accounting.rule.unknown.data.integrity.issue",
@@ -104,84 +112,204 @@ public class AccountingRuleWritePlatformServiceJpaRepositoryImpl implements Acco
// get the GL Accounts or tags to Debit and Credit
final String[] debitTags = command.arrayValueOfParameterNamed(AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue());
final String[] creditTags = command.arrayValueOfParameterNamed(AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue());
final Set<String> incomingDebitTags = new HashSet<String>(Arrays.asList(debitTags));
final Set<String> incomingCreditTags = new HashSet<String>(Arrays.asList(creditTags));
final Long accountToDebitId = command.longValueOfParameterNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue());
final Long accountToCreditId = command.longValueOfParameterNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue());
boolean allowMultipleCreditEntries = false;
boolean allowMultipleDebitEntries = false;
GLAccount debitAccount = null;
GLAccount creditAccount = null;
List<AccountingTagRule> accountingTagRules = new ArrayList<AccountingTagRule>();
if ((accountToDebitId != null && debitTags != null) || (accountToDebitId == null && debitTags == null)) {
// TODO- Throw Appropriate exception
throw new RuntimeException("Please Specify debitTags or accountToDebitId");
throw new AccountingRuleDataException(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue(),
AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue());
} else if (accountToDebitId != null) {
debitAccount = this.accountRepositoryWrapper.findOneWithNotFoundDetection(accountToDebitId);
} else if (debitTags != null) {
accountingTagRules = saveDebitOrCreditTags(debitTags, JournalEntryType.DEBIT, accountingTagRules);
accountingTagRules = saveDebitOrCreditTags(incomingDebitTags, JournalEntryType.DEBIT, accountingTagRules);
allowMultipleDebitEntries = command
.booleanPrimitiveValueOfParameterNamed(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_DEBIT_ENTRIES.getValue());
}
if ((accountToCreditId != null && creditTags != null) || (accountToCreditId == null && creditTags == null)) {
// TODO- Throw Appropriate exception
throw new RuntimeException("Please Specify debitTags or accountToDebitId");
throw new AccountingRuleDataException(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue(),
AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue());
} else if (accountToCreditId != null) {
creditAccount = this.accountRepositoryWrapper.findOneWithNotFoundDetection(accountToCreditId);
} else if (creditTags != null) {
accountingTagRules = saveDebitOrCreditTags(creditTags, JournalEntryType.CREDIT, accountingTagRules);
accountingTagRules = saveDebitOrCreditTags(incomingCreditTags, JournalEntryType.CREDIT, accountingTagRules);
allowMultipleCreditEntries = command
.booleanPrimitiveValueOfParameterNamed(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_CREDIT_ENTRIES.getValue());
}
final AccountingRule accountingRule = AccountingRule.fromJson(office, debitAccount, creditAccount, command);
accountingTagRules = accountingRule.updateAccountingRuleForTags(accountingTagRules);
final AccountingRule accountingRule = AccountingRule.fromJson(office, debitAccount, creditAccount, command,
allowMultipleCreditEntries, allowMultipleDebitEntries);
accountingRule.updateAccountingRuleForTags(accountingTagRules);
return accountingRule;
}
// TODO- This update mehtod should update based on new changes made for
// createAccountingRule.
@Transactional
@Override
public CommandProcessingResult updateAccountingRule(final Long accountingRuleId, final JsonCommand command) {
this.fromApiJsonDeserializer.validateForUpdate(command.json());
try {
Long officeId = null;
if (command.parameterExists(AccountingRuleJsonInputParams.OFFICE_ID.getValue())) {
officeId = command.longValueOfParameterNamed(AccountingRuleJsonInputParams.OFFICE_ID.getValue());
this.fromApiJsonDeserializer.validateForUpdate(command.json());
Long officeId = null;
if (command.parameterExists(AccountingRuleJsonInputParams.OFFICE_ID.getValue())) {
officeId = command.longValueOfParameterNamed(AccountingRuleJsonInputParams.OFFICE_ID.getValue());
}
Long accountToDebitId = null;
if (command.parameterExists(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue())) {
accountToDebitId = command.longValueOfParameterNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue());
}
Long accountToCreditId = null;
if (command.parameterExists(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue())) {
accountToCreditId = command.longValueOfParameterNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue());
}
String[] debitTags = null;
if (command.parameterExists(AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue())) {
debitTags = command.arrayValueOfParameterNamed(AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue());
}
String[] creditTags = null;
if (command.parameterExists(AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue())) {
creditTags = command.arrayValueOfParameterNamed(AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue());
}
if (accountToDebitId != null && debitTags != null) { throw new AccountingRuleDataException(
AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue(), AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue()); }
if (accountToCreditId != null && creditTags != null) { throw new AccountingRuleDataException(
AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue(),
AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue()); }
boolean allowMultipleCreditEntries = false;
if (command.parameterExists(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_CREDIT_ENTRIES.getValue())) {
allowMultipleCreditEntries = command
.booleanPrimitiveValueOfParameterNamed(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_CREDIT_ENTRIES.getValue());
}
boolean allowMultipleDebitEntries = false;
if (command.parameterExists(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_DEBIT_ENTRIES.getValue())) {
allowMultipleDebitEntries = command
.booleanPrimitiveValueOfParameterNamed(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_DEBIT_ENTRIES.getValue());
}
final AccountingRule accountingRule = this.accountingRuleRepositoryWrapper.findOneWithNotFoundDetection(accountingRuleId);
final Map<String, Object> changesOnly = accountingRule.update(command);
if (accountToDebitId != null && changesOnly.containsKey(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue())) {
final GLAccount accountToDebit = this.accountRepositoryWrapper.findOneWithNotFoundDetection(accountToDebitId);
accountingRule.updateDebitAccount(accountToDebit);
accountingRule.updateTags(JournalEntryType.CREDIT);
}
if (accountToCreditId != null && changesOnly.containsKey(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue())) {
final GLAccount accountToCredit = this.accountRepositoryWrapper.findOneWithNotFoundDetection(accountToCreditId);
accountingRule.updateCreditAccount(accountToCredit);
accountingRule.updateTags(JournalEntryType.DEBIT);
}
if (creditTags != null && creditTags.length > 0
&& command.parameterExists(AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue())) {
final Set<String> creditTagsToAdd = determineCreditTagToAddAndRemoveOldTags(creditTags, JournalEntryType.CREDIT,
accountingRule);
if (!creditTagsToAdd.isEmpty()) {
List<AccountingTagRule> accountingTagRules = new ArrayList<AccountingTagRule>();
accountingTagRules = saveDebitOrCreditTags(creditTagsToAdd, JournalEntryType.CREDIT, accountingTagRules);
accountingRule.updateAccountingRuleForTags(accountingTagRules);
accountingRule.updateCreditAccount(null);
if (allowMultipleCreditEntries) {
accountingRule.updateAllowMultipleCreditEntries(allowMultipleCreditEntries);
}
changesOnly.put(AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue(), creditTagsToAdd);
}
}
if (debitTags != null && debitTags.length > 0
&& command.parameterExists(AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue())) {
final Set<String> debitTagsToAdd = determineCreditTagToAddAndRemoveOldTags(debitTags, JournalEntryType.DEBIT,
accountingRule);
if (!debitTagsToAdd.isEmpty()) {
List<AccountingTagRule> accountingTagRules = new ArrayList<AccountingTagRule>();
accountingTagRules = saveDebitOrCreditTags(debitTagsToAdd, JournalEntryType.DEBIT, accountingTagRules);
accountingRule.updateAccountingRuleForTags(accountingTagRules);
accountingRule.updateDebitAccount(null);
if (allowMultipleDebitEntries) {
accountingRule.updateAllowMultipleDebitEntries(allowMultipleDebitEntries);
}
changesOnly.put(AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue(), debitTagsToAdd);
}
}
if (officeId != null && changesOnly.containsKey(AccountingRuleJsonInputParams.OFFICE_ID.getValue())) {
final Office userOffice = this.officeRepository.findOne(officeId);
if (userOffice == null) { throw new OfficeNotFoundException(officeId); }
accountingRule.setOffice(userOffice);
}
if (!changesOnly.isEmpty()) {
this.accountingRuleRepository.saveAndFlush(accountingRule);
}
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(accountingRule.getId())
.with(changesOnly).build();
} catch (final DataIntegrityViolationException dve) {
handleAccountingRuleIntegrityIssues(command, dve);
return CommandProcessingResult.empty();
}
Long accountToDebitId = null;
if (command.parameterExists(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue())) {
accountToDebitId = command.longValueOfParameterNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue());
}
private Set<String> determineCreditTagToAddAndRemoveOldTags(final String[] creditOrDebitTags, final JournalEntryType type,
final AccountingRule accountingRule) {
final Set<String> incomingTags = new HashSet<String>(Arrays.asList(creditOrDebitTags));
final Set<AccountingTagRule> existingTags = accountingRule.getAccountingTagRulesByType(type);
final Set<String> existingTagIds = retrieveExistingTagIds(existingTags);
final Set<String> tagsToAdd = new HashSet<String>();
final Set<String> tagsToRemove = existingTagIds;
final Map<Long, AccountingTagRule> accountsToRemove = new HashMap<Long, AccountingTagRule>();
for (final String tagId : incomingTags) {
if (existingTagIds.contains(tagId)) {
tagsToRemove.remove(tagId);
} else {
tagsToAdd.add(tagId);
}
}
Long accountToCreditId = null;
if (command.parameterExists(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue())) {
accountToCreditId = command.longValueOfParameterNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue());
if (!tagsToRemove.isEmpty()) {
for (final String tagId : tagsToRemove) {
for (final AccountingTagRule accountingTagRule : existingTags) {
if (tagId.equals(accountingTagRule.getTagId().toString())) {
accountsToRemove.put(accountingTagRule.getId(), accountingTagRule);
}
}
}
accountingRule.removeOldTags(new ArrayList<AccountingTagRule>(accountsToRemove.values()));
}
return tagsToAdd;
}
final AccountingRule accountingRule = this.accountingRuleRepositoryWrapper.findOneWithNotFoundDetection(accountingRuleId);
final Map<String, Object> changesOnly = accountingRule.update(command);
if (accountToDebitId != null && changesOnly.containsKey(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue())) {
final GLAccount accountToDebit = this.accountRepositoryWrapper.findOneWithNotFoundDetection(accountToDebitId);
accountingRule.setAccountToDebit(accountToDebit);
private Set<String> retrieveExistingTagIds(final Set<AccountingTagRule> existingCreditTags) {
final Set<String> existingCreditTagIds = new HashSet<String>();
for (final AccountingTagRule accountingTagRule : existingCreditTags) {
existingCreditTagIds.add(accountingTagRule.getTagId().toString());
}
if (accountToCreditId != null && changesOnly.containsKey(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue())) {
final GLAccount accountToCredit = this.accountRepositoryWrapper.findOneWithNotFoundDetection(accountToCreditId);
accountingRule.setAccountToCredit(accountToCredit);
}
if (officeId != null && changesOnly.containsKey(AccountingRuleJsonInputParams.OFFICE_ID.getValue())) {
final Office userOffice = this.officeRepository.findOne(officeId);
if (userOffice == null) { throw new OfficeNotFoundException(officeId); }
accountingRule.setOffice(userOffice);
}
if (!changesOnly.isEmpty()) {
this.accountingRuleRepository.saveAndFlush(accountingRule);
}
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(accountingRule.getId())
.with(changesOnly).build();
return existingCreditTagIds;
}
@Transactional
@@ -192,27 +320,16 @@ public class AccountingRuleWritePlatformServiceJpaRepositoryImpl implements Acco
return new CommandProcessingResultBuilder().withEntityId(accountingRule.getId()).build();
}
/* private GLAccount saveDebitOrCreditTagsOrGetDebitORCreditAccount(final String[] creditOrDebitTagArray, final Long creditOrDebitId,
final JournalEntryType transactionType) {
GLAccount creditOrDebitAccount = null;
if (creditOrDebitId != null) {
creditOrDebitAccount = this.accountRepositoryWrapper.findOneWithNotFoundDetection(creditOrDebitId);
} else if (creditOrDebitTagArray != null) {
final List<AccountingTagRule> accountingTagRules = saveDebitOrCreditTags(creditOrDebitTagArray, transactionType);
} else {
throw new RuntimeException("Please Specify debitTags or accountToDebitId");
}
return creditOrDebitAccount;
}*/
private List<AccountingTagRule> saveDebitOrCreditTags(final String[] creditOrDebitTagArray, final JournalEntryType transactionType,
private List<AccountingTagRule> saveDebitOrCreditTags(final Set<String> creditOrDebitTagArray, final JournalEntryType transactionType,
final List<AccountingTagRule> accountingTagRules) {
for (final String creditOrDebitTag : creditOrDebitTagArray) {
final Long creditOrDebitTagIdLongValue = Long.valueOf(creditOrDebitTag);
final CodeValue creditOrDebitAccount = this.codeValueRepository.findOne(creditOrDebitTagIdLongValue);
if (creditOrDebitAccount == null) { throw new CodeValueNotFoundException(creditOrDebitTagIdLongValue); }
final AccountingTagRule accountingTagRule = AccountingTagRule.create(creditOrDebitAccount, transactionType.getValue());
accountingTagRules.add(accountingTagRule);
if (creditOrDebitTag != null && StringUtils.isNotBlank(creditOrDebitTag)) {
final Long creditOrDebitTagIdLongValue = Long.valueOf(creditOrDebitTag);
final CodeValue creditOrDebitAccount = this.codeValueRepository.findOne(creditOrDebitTagIdLongValue);
if (creditOrDebitAccount == null) { throw new CodeValueNotFoundException(creditOrDebitTagIdLongValue); }
final AccountingTagRule accountingTagRule = AccountingTagRule.create(creditOrDebitAccount, transactionType.getValue());
accountingTagRules.add(accountingTagRule);
}
}
return accountingTagRules;
}
@@ -10,7 +10,6 @@ package org.mifosplatform.infrastructure.codes.data;
*/
public class CodeValueData {
@SuppressWarnings("unused")
private final Long id;
@SuppressWarnings("unused")
@@ -32,4 +31,8 @@ public class CodeValueData {
this.name = name;
this.position = position;
}
public Long getId() {
return id;
}
}