diff --git a/mifosng-db/migrations/core_db/V45__create_acc_rule_tags_table.sql b/mifosng-db/migrations/core_db/V45__create_acc_rule_tags_table.sql new file mode 100644 index 000000000..b17bc2e01 --- /dev/null +++ b/mifosng-db/migrations/core_db/V45__create_acc_rule_tags_table.sql @@ -0,0 +1,11 @@ +create table `acc_rule_tags` ( + `id` BIGINT(20) NOT NULL AUTO_INCREMENT, + `acc_rule_id` BIGINT(20) NOT NULL, + `tag_id` INT(11) NOT NULL, + `acc_type_enum` SMALLINT(5) NOT NULL, + primary key(`id`), + INDEX `FK_acc_accounting_rule_id` (`acc_rule_id`), + INDEX `FK_m_code_value_id` (`tag_id`), + CONSTRAINT `FK_acc_accounting_rule_id` FOREIGN KEY (`acc_rule_id`) REFERENCES `acc_accounting_rule` (`id`), + CONSTRAINT `FK_m_code_value_id` FOREIGN KEY (`tag_id`) REFERENCES `m_code_value` (`id`) +); \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryWritePlatformServiceJpaRepositoryImpl.java index 4f04299cf..dd3e63383 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/JournalEntryWritePlatformServiceJpaRepositoryImpl.java @@ -112,7 +112,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa validateGLAccountForTransaction(creditAccountHead); final GLAccount debitAccountHead = accountingRule.getAccountToDebit(); validateGLAccountForTransaction(debitAccountHead); - String description = accountingRule.getDescription(); + String description = null; if (StringUtils.isNotBlank(journalEntryCommand.getComments())) { description = journalEntryCommand.getComments(); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/api/AccountingRuleApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/api/AccountingRuleApiResource.java index a5701ab94..961847d75 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/api/AccountingRuleApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/api/AccountingRuleApiResource.java @@ -6,6 +6,7 @@ package org.mifosplatform.accounting.rule.api; import java.util.Arrays; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -23,6 +24,7 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.UriInfo; +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; @@ -30,6 +32,8 @@ import org.mifosplatform.accounting.rule.service.AccountingRuleReadPlatformServi 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.ApiRequestParameterHelper; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; @@ -47,7 +51,9 @@ import org.springframework.stereotype.Component; public class AccountingRuleApiResource { private static final Set RESPONSE_DATA_PARAMETERS = new HashSet(Arrays.asList("id", "officeId", "officeName", - "accountToDebitId", "accountToCreditId", "name", "description", "systemDefined")); + "accountToDebitId", "accountToCreditId", "name", "description", "systemDefined", "allowedAssetsTagOptions", + "allowedLiabilitiesTagOptions", "allowedEquityTagOptions", "allowedIncomeTagOptions", "allowedExpensesTagOptions", "debitTags", + "creditTags")); private final String resourceNameForPermission = "ACCOUNTINGRULE"; @@ -58,6 +64,7 @@ public class AccountingRuleApiResource { private final ApiRequestParameterHelper apiRequestParameterHelper; private final PlatformSecurityContext context; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; + private final CodeValueReadPlatformService codeValueReadPlatformService; @Autowired public AccountingRuleApiResource(final PlatformSecurityContext context, @@ -65,7 +72,7 @@ public class AccountingRuleApiResource { final DefaultToApiJsonSerializer toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper, final GLAccountReadPlatformService accountReadPlatformService, final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService, - final OfficeReadPlatformService officeReadPlatformService) { + final OfficeReadPlatformService officeReadPlatformService, final CodeValueReadPlatformService codeValueReadPlatformService) { this.context = context; this.apiRequestParameterHelper = apiRequestParameterHelper; this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; @@ -73,22 +80,23 @@ public class AccountingRuleApiResource { this.accountingRuleReadPlatformService = accountingRuleReadPlatformService; this.officeReadPlatformService = officeReadPlatformService; this.accountReadPlatformService = accountReadPlatformService; + this.codeValueReadPlatformService = codeValueReadPlatformService; } - + @GET - @Path("template") - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) - public String retrieveTemplate(@Context final UriInfo uriInfo) { - - context.authenticatedUser().validateHasReadPermission(resourceNameForPermission); - - AccountingRuleData accountingRuleData = null; - accountingRuleData = handleTemplate(accountingRuleData); - - final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); - return this.apiJsonSerializerService.serialize(settings, accountingRuleData, RESPONSE_DATA_PARAMETERS); - } + @Path("template") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveTemplate(@Context final UriInfo uriInfo) { + + this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission); + + AccountingRuleData accountingRuleData = null; + accountingRuleData = handleTemplate(accountingRuleData); + + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + return this.apiJsonSerializerService.serialize(settings, accountingRuleData, RESPONSE_DATA_PARAMETERS); + } @GET @Consumes({ MediaType.APPLICATION_JSON }) @@ -114,7 +122,7 @@ public class AccountingRuleApiResource { AccountingRuleData accountingRuleData = this.accountingRuleReadPlatformService.retrieveAccountingRuleById(accountingRuleId); if (settings.isTemplate()) { - accountingRuleData = handleTemplate(accountingRuleData); + accountingRuleData = handleTemplate(accountingRuleData); } return this.apiJsonSerializerService.serialize(settings, accountingRuleData, RESPONSE_DATA_PARAMETERS); @@ -157,13 +165,31 @@ public class AccountingRuleApiResource { return this.apiJsonSerializerService.serialize(result); } - - private AccountingRuleData handleTemplate(AccountingRuleData accountingRuleData) { - List allowedAccounts = this.accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(); - List allowedOffices = (List) this.officeReadPlatformService.retrieveAllOfficesForDropdown(); - if (accountingRuleData == null) { - return new AccountingRuleData(allowedAccounts, allowedOffices); - } - return new AccountingRuleData(accountingRuleData, allowedAccounts, allowedOffices); - } + + private AccountingRuleData handleTemplate(final AccountingRuleData accountingRuleData) { + final List allowedAccounts = this.accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(); + final List allowedOffices = (List) this.officeReadPlatformService.retrieveAllOfficesForDropdown(); + final Collection allowedAssetsTagOptions = defaultIfEmpty(this.codeValueReadPlatformService + .retrieveCodeValuesByCode(AccountingConstants.ASSESTS_TAG_OPTION_CODE_NAME)); + final Collection allowedLiabilitiesTagOptions = defaultIfEmpty(this.codeValueReadPlatformService + .retrieveCodeValuesByCode(AccountingConstants.LIABILITIES_TAG_OPTION_CODE_NAME)); + final Collection allowedEquityTagOptions = defaultIfEmpty(this.codeValueReadPlatformService + .retrieveCodeValuesByCode(AccountingConstants.EQUITY_TAG_OPTION_CODE_NAME)); + final Collection allowedIncomeTagOptions = defaultIfEmpty(this.codeValueReadPlatformService + .retrieveCodeValuesByCode(AccountingConstants.INCOME_TAG_OPTION_CODE_NAME)); + final Collection 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); + } + + private Collection defaultIfEmpty(final Collection collection) { + Collection returnCollection = null; + if (collection != null && !collection.isEmpty()) { + returnCollection = collection; + } + return returnCollection; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/api/AccountingRuleJsonInputParams.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/api/AccountingRuleJsonInputParams.java index e50fcde0b..161638bbe 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/api/AccountingRuleJsonInputParams.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/api/AccountingRuleJsonInputParams.java @@ -13,7 +13,7 @@ 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"); + "description"), SYSTEM_DEFINED("systemDefined"), DEBIT_ACCOUNT_TAGS("debitTags"), CREDIT_ACCOUNT_TAGS("creditTags"); private final String value; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/data/AccountingRuleData.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/data/AccountingRuleData.java index 248c3204d..9b8d1acdb 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/data/AccountingRuleData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/data/AccountingRuleData.java @@ -6,9 +6,11 @@ package org.mifosplatform.accounting.rule.data; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import org.mifosplatform.accounting.glaccount.data.GLAccountData; +import org.mifosplatform.infrastructure.codes.data.CodeValueData; import org.mifosplatform.organisation.office.data.OfficeData; /** @@ -19,85 +21,127 @@ import org.mifosplatform.organisation.office.data.OfficeData; */ public class AccountingRuleData { - private final Long id; - private final Long officeId; - private final String officeName; - private final String name; - private final String description; - private final boolean systemDefined; - private final GLAccountData debitAccountHead; - private final GLAccountData creditAccountHead; + private final Long id; + private final Long officeId; + private final String officeName; + private final String name; + private final String description; + private final boolean systemDefined; + private final GLAccountData debitAccountHead; + private final GLAccountData creditAccountHead; + private final List creditTags; + private final List debitTags; - // template - @SuppressWarnings("unused") - private List allowedOffices = new ArrayList(); - @SuppressWarnings("unused") - private List allowedAccounts = new ArrayList(); + // template + private List allowedOffices = new ArrayList(); + private List allowedAccounts = new ArrayList(); + private final Collection allowedAssetsTagOptions; + private final Collection allowedLiabilitiesTagOptions; + private final Collection allowedEquityTagOptions; + private final Collection allowedIncomeTagOptions; + private final Collection allowedExpensesTagOptions; - /*public AccountingRuleData(final Long id, final Long accountToDebitId, final Long accountToCreditId) { - this(id, null, null, accountToDebitId, accountToCreditId, null, null, true, null, null, null, null, null, null); - }*/ + public AccountingRuleData(final AccountingRuleData accountingRuleData, final List allowedAccounts, + final List allowedOffices, final Collection allowedAssetsTagOptions, + final Collection allowedLiabilitiesTagOptions, final Collection allowedEquityTagOptions, + final Collection allowedIncomeTagOptions, final Collection allowedExpensesTagOptions) { + 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.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.creditTags = accountingRuleData.creditTags; + this.debitTags = accountingRuleData.debitTags; + } - /*public AccountingRuleData(final Long id, final Long officeId, final String officeName, final Long accountToDebitId, - final Long accountToCreditId, final String name, final String description, final boolean systemDefined, - final String debitAccountName, final String creditAccountName, final String debitAccountGLCode, - final String creditAccountGLCode) { - this(id, officeId, officeName, accountToDebitId, accountToCreditId, name, description, systemDefined, debitAccountName, - creditAccountName, debitAccountGLCode, creditAccountGLCode, null, null); - }*/ + public AccountingRuleData(final List allowedAccounts, final List allowedOffices, + final Collection allowedAssetsTagOptions, final Collection allowedLiabilitiesTagOptions, + final Collection allowedEquityTagOptions, final Collection allowedIncomeTagOptions, + final Collection allowedExpensesTagOptions) { + this.id = null; + this.officeId = null; + this.officeName = null; + this.name = null; + this.description = null; + this.systemDefined = 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.creditTags = null; + this.debitTags = null; + } - public AccountingRuleData(final Long id, final Long officeId, final String officeName, final String name, final String description, - final boolean systemDefined, final List allowedOffices, final List allowedAccounts) { - this.id = id; - this.officeId = officeId; - this.officeName = officeName; - this.name = name; - this.description = description; - this.systemDefined = systemDefined; - this.allowedOffices = allowedOffices; - this.allowedAccounts = allowedAccounts; - this.debitAccountHead = null; - this.creditAccountHead = null; - } + 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) { + this.id = id; + this.officeId = officeId; + this.officeName = officeName; + this.name = name; + this.description = description; + this.systemDefined = systemDefined; + 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.creditTags = null; + this.debitTags = null; + } - public AccountingRuleData(final AccountingRuleData accountingRuleData, - final List allowedAccounts, final List allowedOffices) { - 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.allowedOffices = allowedOffices; - this.allowedAccounts = allowedAccounts; - this.debitAccountHead = accountingRuleData.debitAccountHead; - this.creditAccountHead = accountingRuleData.creditAccountHead; - } + public AccountingRuleData(final AccountingRuleData accountingRuleData, final List creditTags, + final List debitTags) { + 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.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.creditTags = creditTags; + this.debitTags = debitTags; + } - public AccountingRuleData(final List allowedAccounts, final List allowedOffices) { - this.id = null; - this.officeId = null; - this.officeName = null; - this.name = null; - this.description = null; - this.systemDefined = false; - this.allowedOffices = allowedOffices; - this.allowedAccounts = allowedAccounts; - this.debitAccountHead = null; - this.creditAccountHead = null; - } + public GLAccountData getDebitAccountHead() { + return this.debitAccountHead; + } - public AccountingRuleData(Long id, Long officeId, String officeName, String name, String description, - boolean systemDefined, GLAccountData debitAccountData, GLAccountData creditAccountData) { - this.id = id; - this.officeId = officeId; - this.officeName = officeName; - this.name = name; - this.description = description; - this.systemDefined = systemDefined; - this.allowedOffices = null; - this.allowedAccounts = null; - this.debitAccountHead = debitAccountData; - this.creditAccountHead = creditAccountData; - } + public GLAccountData getCreditAccountHead() { + return this.creditAccountHead; + } + + public List getCreditTags() { + return this.creditTags; + } + + public List getDebitTags() { + return this.debitTags; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/data/AccountingTagRuleData.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/data/AccountingTagRuleData.java new file mode 100644 index 000000000..f4988b7d9 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/data/AccountingTagRuleData.java @@ -0,0 +1,20 @@ +package org.mifosplatform.accounting.rule.data; + +import org.mifosplatform.infrastructure.core.data.EnumOptionData; + +public class AccountingTagRuleData { + + @SuppressWarnings("unused") + private final Long id; + @SuppressWarnings("unused") + private final Long tagId; + @SuppressWarnings("unused") + private final EnumOptionData transactionType; + + public AccountingTagRuleData(final Long id, final Long tagId, final EnumOptionData transactionType) { + this.id = id; + this.tagId = tagId; + this.transactionType = transactionType; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/domain/AccountingRule.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/domain/AccountingRule.java index f934efe68..1b30eb02e 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/domain/AccountingRule.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/domain/AccountingRule.java @@ -5,17 +5,23 @@ */ package org.mifosplatform.accounting.rule.domain; +import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.UniqueConstraint; 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.rule.api.AccountingRuleJsonInputParams; import org.mifosplatform.infrastructure.core.api.JsonCommand; @@ -34,11 +40,11 @@ public class AccountingRule extends AbstractPersistable { private Office office; @ManyToOne - @JoinColumn(name = "debit_account_id", nullable = false) + @JoinColumn(name = "debit_account_id", nullable = true) private GLAccount accountToDebit; @ManyToOne - @JoinColumn(name = "credit_account_id", nullable = false) + @JoinColumn(name = "credit_account_id", nullable = true) private GLAccount accountToCredit; @Column(name = "description", nullable = true, length = 500) @@ -46,6 +52,11 @@ public class AccountingRule extends AbstractPersistable { @Column(name = "system_defined", nullable = false) private Boolean systemDefined; + + @LazyCollection(LazyCollectionOption.FALSE) + @OneToMany(cascade = CascadeType.ALL, mappedBy = "accountingRule", orphanRemoval = true) + private List accountingTagRules = new ArrayList(); + protected AccountingRule() {} @@ -151,4 +162,12 @@ public class AccountingRule extends AbstractPersistable { return this.description; } + public List updateAccountingRuleForTags(List debitAccountingTagRules) { + for(AccountingTagRule accountingTagRule : debitAccountingTagRules){ + accountingTagRule.updateAccountingTagRule(this); + this.accountingTagRules.add(accountingTagRule); + } + return debitAccountingTagRules; + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/domain/AccountingTagRule.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/domain/AccountingTagRule.java new file mode 100644 index 000000000..f83aa310e --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/domain/AccountingTagRule.java @@ -0,0 +1,40 @@ +package org.mifosplatform.accounting.rule.domain; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import org.mifosplatform.infrastructure.codes.domain.CodeValue; +import org.springframework.data.jpa.domain.AbstractPersistable; + +@Entity +@Table(name = "acc_rule_tags") +public class AccountingTagRule extends AbstractPersistable { + + @ManyToOne + @JoinColumn(name = "acc_rule_id", nullable = false) + private AccountingRule accountingRule; + + @ManyToOne + @JoinColumn(name = "tag_id", nullable = false) + private final CodeValue tagId; + + @Column(name = "acc_type_enum", nullable = false) + private final Integer accountType; + + public static AccountingTagRule create(final CodeValue tagId, final Integer accountType) { + return new AccountingTagRule(tagId, accountType); + } + + public AccountingTagRule(final CodeValue tagId, final Integer accountType) { + this.tagId = tagId; + this.accountType = accountType; + } + + public void updateAccountingTagRule(final AccountingRule accountingRule) { + this.accountingRule = accountingRule; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/serialization/AccountingRuleCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/serialization/AccountingRuleCommandFromApiJsonDeserializer.java index 07c2a0be1..d74429434 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/serialization/AccountingRuleCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/serialization/AccountingRuleCommandFromApiJsonDeserializer.java @@ -55,7 +55,8 @@ public final class AccountingRuleCommandFromApiJsonDeserializer extends Abstract element); final String name = this.fromApiJsonHelper.extractStringNamed(AccountingRuleJsonInputParams.NAME.getValue(), element); 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); return new AccountingRuleCommand(id, officeId, accountToDebitId, accountToCreditId, name, description); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/service/AccountingRuleDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/service/AccountingRuleDataValidator.java new file mode 100644 index 000000000..76ac1d5b5 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/service/AccountingRuleDataValidator.java @@ -0,0 +1,147 @@ +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 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>() {}.getType(); + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters); + + final List dataValidationErrors = new ArrayList(); + 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 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>() {}.getType(); + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters); + + final List dataValidationErrors = new ArrayList(); + 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); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/service/AccountingRuleReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/service/AccountingRuleReadPlatformService.java index d33b7fef7..1ea43a58d 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/service/AccountingRuleReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/service/AccountingRuleReadPlatformService.java @@ -13,6 +13,6 @@ public interface AccountingRuleReadPlatformService { List retrieveAllAccountingRules(Long OfficeId); - AccountingRuleData retrieveAccountingRuleById(long accountingRuleId); + AccountingRuleData retrieveAccountingRuleById(Long accountingRuleId); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/service/AccountingRuleReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/service/AccountingRuleReadPlatformServiceImpl.java index 369d7586d..de1a9d6d3 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/service/AccountingRuleReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/service/AccountingRuleReadPlatformServiceImpl.java @@ -7,16 +7,25 @@ package org.mifosplatform.accounting.rule.service; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import org.mifosplatform.accounting.common.AccountingEnumerations; import org.mifosplatform.accounting.glaccount.data.GLAccountData; +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.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.domain.JdbcSupport; import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Service; @@ -30,13 +39,15 @@ public class AccountingRuleReadPlatformServiceImpl implements AccountingRuleRead this.jdbcTemplate = new JdbcTemplate(dataSource); } - private static final class AccountingRuleMapper implements RowMapper { + // Will remove the old one if everything goes well. +/* private static final class AccountingRuleMapper implements RowMapper { 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,") + 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,") @@ -46,7 +57,7 @@ public class AccountingRuleReadPlatformServiceImpl implements AccountingRuleRead .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"); + .append("where debitAccount.id=rule.debit_account_id and creditAccount.id = rule.credit_account_id"); this.schemaSql = sqlBuilder.toString(); } @@ -66,41 +77,137 @@ public class AccountingRuleReadPlatformServiceImpl implements AccountingRuleRead 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); + 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); } - } + }*/ - @Override - public List retrieveAllAccountingRules(Long officeId) { - final AccountingRuleMapper rm = new AccountingRuleMapper(); - Object[] arguments = new Object[]{}; - String sql = "select " + rm.schema() +" and system_defined=0 "; - if(officeId != null) { - sql = sql +" and office.id = ?"; - arguments = new Object[] { officeId }; + private static final class AccountingRuleDataExtractor implements ResultSetExtractor { + + private final String schemaSql; + private final JdbcTemplate jdbcTemplate; + + public AccountingRuleDataExtractor(final JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + 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("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 ") + .append(" LEFT JOIN acc_gl_account AS creditAccount ON rule.credit_account_id = creditAccount.id ") + .append(" LEFT JOIN acc_gl_account AS debitAccount ON rule.debit_account_id = debitAccount.id ") + .append("WHERE office.id=rule.office_id "); + this.schemaSql = sqlBuilder.toString(); } - sql = sql + " order by rule.id asc"; - return this.jdbcTemplate.query(sql, rm, arguments); + + public String schema() { + return this.schemaSql; + } + + @Override + public Map extractData(final ResultSet rs) throws SQLException, DataAccessException { + final Map extractedData = new HashMap(); + + while (rs.next()) { + final Long id = rs.getLong("id"); + AccountingRuleData accountingRuleData = extractedData.get(id); + if (accountingRuleData == null) { + 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 = JdbcSupport.getLong(rs, "debitAccountId"); + final Long accountToCreditId = JdbcSupport.getLong(rs, "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 = accountToDebitId == null ? null : new GLAccountData(accountToDebitId, + debitAccountName, debitAccountGLCode); + final GLAccountData creditAccountData = accountToCreditId == null ? null : new GLAccountData(accountToCreditId, + creditAccountName, creditAccountGLCode); + accountingRuleData = new AccountingRuleData(id, officeId, officeName, name, description, systemDefined, + debitAccountData, creditAccountData); + } + if (accountingRuleData.getCreditAccountHead() == null) { + final List creditTags = getCreditOrDebitTags(id, JournalEntryType.CREDIT.getValue()); + accountingRuleData = new AccountingRuleData(accountingRuleData, creditTags, accountingRuleData.getDebitTags()); + } + if (accountingRuleData.getDebitAccountHead() == null) { + final List debitTags = getCreditOrDebitTags(id, JournalEntryType.DEBIT.getValue()); + accountingRuleData = new AccountingRuleData(accountingRuleData, accountingRuleData.getCreditTags(), debitTags); + } + extractedData.put(id, accountingRuleData); + } + return extractedData; + } + + private List getCreditOrDebitTags(final Long creditOrDebitAccount, final Integer transactionType) { + final AccountingTagRuleDataMapper mapper = new AccountingTagRuleDataMapper(); + final String taggedAccountsSchema = "Select " + mapper.taggedAccountSchema() + " where rule.id = ? and tag.acc_type_enum=?"; + return this.jdbcTemplate.query(taggedAccountsSchema, mapper, new Object[] { creditOrDebitAccount, transactionType }); + } + } @Override - public AccountingRuleData retrieveAccountingRuleById(long accountingRuleId) { + public List retrieveAllAccountingRules(final Long officeId) { + final AccountingRuleDataExtractor resultSetExtractor = new AccountingRuleDataExtractor(this.jdbcTemplate); + Object[] arguments = new Object[] {}; + String sql = "select " + resultSetExtractor.schema() + " and system_defined=0 "; + if (officeId != null) { + sql = sql + " and office.id = ?"; + arguments = new Object[] { officeId }; + } + sql = sql + " order by rule.id asc"; + @SuppressWarnings("unchecked") + final Map extractedData = (Map) this.jdbcTemplate.query(sql, + resultSetExtractor, arguments); + return new ArrayList(extractedData.values()); + } + + @Override + public AccountingRuleData retrieveAccountingRuleById(final Long accountingRuleId) { try { + final AccountingRuleDataExtractor resultSetExtractor = new AccountingRuleDataExtractor(this.jdbcTemplate); + final String sql = "select " + resultSetExtractor.schema() + " and rule.id = ?"; - final AccountingRuleMapper rm = new AccountingRuleMapper(); - final String sql = "select " + rm.schema() + " and rule.id = ?"; - - final AccountingRuleData accountingRuleData = this.jdbcTemplate.queryForObject(sql, rm, new Object[] { accountingRuleId }); + @SuppressWarnings("unchecked") + final Map extractedData = (Map) this.jdbcTemplate.query(sql, + resultSetExtractor, new Object[] { accountingRuleId }); + final AccountingRuleData accountingRuleData = extractedData.get(accountingRuleId); + if (accountingRuleData == null) { throw new AccountingRuleNotFoundException(accountingRuleId); } return accountingRuleData; } catch (final EmptyResultDataAccessException e) { throw new AccountingRuleNotFoundException(accountingRuleId); } } + + private static final class AccountingTagRuleDataMapper implements RowMapper { + + public String taggedAccountSchema() { + return " tag.id as id,tag.tag_id as tagId, tag.acc_type_enum as transactionType from acc_rule_tags tag " + + "join acc_accounting_rule rule on tag.acc_rule_id=rule.id "; + } + + @Override + public AccountingTagRuleData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + final Long id = rs.getLong("id"); + final Long tagId = rs.getLong("tagId"); + final Integer transactionType = JdbcSupport.getInteger(rs, "transactionType"); + final EnumOptionData transactionTypeEnum = AccountingEnumerations.journalEntryType(transactionType); + return new AccountingTagRuleData(id, tagId, transactionTypeEnum); + } + + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/service/AccountingRuleWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/service/AccountingRuleWritePlatformServiceJpaRepositoryImpl.java index f034e06ec..2e38b7516 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/service/AccountingRuleWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/rule/service/AccountingRuleWritePlatformServiceJpaRepositoryImpl.java @@ -5,18 +5,22 @@ */ package org.mifosplatform.accounting.rule.service; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import org.mifosplatform.accounting.closure.api.GLClosureJsonInputParams; import org.mifosplatform.accounting.glaccount.domain.GLAccount; import org.mifosplatform.accounting.glaccount.domain.GLAccountRepositoryWrapper; +import org.mifosplatform.accounting.journalentry.domain.JournalEntryType; import org.mifosplatform.accounting.rule.api.AccountingRuleJsonInputParams; -import org.mifosplatform.accounting.rule.command.AccountingRuleCommand; 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.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.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; @@ -40,17 +44,20 @@ public class AccountingRuleWritePlatformServiceJpaRepositoryImpl implements Acco private final AccountingRuleRepository accountingRuleRepository; private final GLAccountRepositoryWrapper accountRepositoryWrapper; private final OfficeRepository officeRepository; - private final AccountingRuleCommandFromApiJsonDeserializer fromApiJsonDeserializer; + private final AccountingRuleDataValidator fromApiJsonDeserializer; + private final CodeValueRepository codeValueRepository; @Autowired public AccountingRuleWritePlatformServiceJpaRepositoryImpl(final AccountingRuleRepositoryWrapper accountingRuleRepositoryWrapper, final GLAccountRepositoryWrapper accountRepositoryWrapper, final OfficeRepository officeRepository, - final AccountingRuleCommandFromApiJsonDeserializer fromApiJsonDeserializer, final AccountingRuleRepository ruleRepository) { + final AccountingRuleRepository ruleRepository, final AccountingRuleDataValidator fromApiJsonDeserializer, + final CodeValueRepository codeValueRepository) { this.accountRepositoryWrapper = accountRepositoryWrapper; this.officeRepository = officeRepository; - this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.accountingRuleRepository = ruleRepository; this.accountingRuleRepositoryWrapper = accountingRuleRepositoryWrapper; + this.fromApiJsonDeserializer = fromApiJsonDeserializer; + this.codeValueRepository = codeValueRepository; } /** @@ -69,10 +76,10 @@ public class AccountingRuleWritePlatformServiceJpaRepositoryImpl implements Acco @Transactional @Override - public CommandProcessingResult createAccountingRule(JsonCommand command) { + public CommandProcessingResult createAccountingRule(final JsonCommand command) { try { - final AccountingRuleCommand accountingRuleCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json()); - accountingRuleCommand.validateForCreate(); + + this.fromApiJsonDeserializer.validateForCreate(command.json()); // check office is valid final Long officeId = command.longValueOfParameterNamed(GLClosureJsonInputParams.OFFICE_ID.getValue()); @@ -82,15 +89,8 @@ public class AccountingRuleWritePlatformServiceJpaRepositoryImpl implements Acco if (office == null) { throw new OfficeNotFoundException(officeId); } } - // get the GL Accounts to Debit and Credit - final Long accountToDebitId = command.longValueOfParameterNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue()); - final Long accountToCreditId = command.longValueOfParameterNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue()); - final GLAccount accountToDebit = accountRepositoryWrapper.findOneWithNotFoundDetection(accountToDebitId); - final GLAccount accountToCredit = accountRepositoryWrapper.findOneWithNotFoundDetection(accountToCreditId); - - final AccountingRule accountingRule = AccountingRule.fromJson(office, accountToDebit, accountToCredit, command); + final AccountingRule accountingRule = assembleAccountingRuleAndTags(office, command); this.accountingRuleRepository.saveAndFlush(accountingRule); - return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withOfficeId(officeId) .withEntityId(accountingRule.getId()).build(); } catch (final DataIntegrityViolationException dve) { @@ -99,11 +99,43 @@ public class AccountingRuleWritePlatformServiceJpaRepositoryImpl implements Acco } } + private AccountingRule assembleAccountingRuleAndTags(final Office office, final JsonCommand command) { + // 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 Long accountToDebitId = command.longValueOfParameterNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue()); + final Long accountToCreditId = command.longValueOfParameterNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue()); + GLAccount debitAccount = null; + GLAccount creditAccount = null; + List accountingTagRules = new ArrayList(); + + if (accountToDebitId != null) { + debitAccount = this.accountRepositoryWrapper.findOneWithNotFoundDetection(accountToDebitId); + } else if (debitTags != null) { + accountingTagRules = saveDebitOrCreditTags(debitTags, JournalEntryType.DEBIT, accountingTagRules); + } else { + throw new RuntimeException("Please Specify debitTags or accountToDebitId"); + } + + if (accountToCreditId != null) { + creditAccount = this.accountRepositoryWrapper.findOneWithNotFoundDetection(accountToCreditId); + } else if (debitTags != null) { + accountingTagRules = saveDebitOrCreditTags(creditTags, JournalEntryType.CREDIT, accountingTagRules); + } else { + throw new RuntimeException("Please Specify debitTags or accountToDebitId"); + } + + final AccountingRule accountingRule = AccountingRule.fromJson(office, debitAccount, creditAccount, command); + accountingTagRules = accountingRule.updateAccountingRuleForTags(accountingTagRules); + + return accountingRule; + } + @Transactional @Override - public CommandProcessingResult updateAccountingRule(Long accountingRuleId, JsonCommand command) { - final AccountingRuleCommand accountingRuleCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json()); - accountingRuleCommand.validateForUpdate(); + public CommandProcessingResult updateAccountingRule(final Long accountingRuleId, final JsonCommand command) { + + this.fromApiJsonDeserializer.validateForUpdate(command.json()); Long officeId = null; if (command.parameterExists(AccountingRuleJsonInputParams.OFFICE_ID.getValue())) { @@ -124,12 +156,12 @@ public class AccountingRuleWritePlatformServiceJpaRepositoryImpl implements Acco final Map changesOnly = accountingRule.update(command); if (accountToDebitId != null && changesOnly.containsKey(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue())) { - final GLAccount accountToDebit = accountRepositoryWrapper.findOneWithNotFoundDetection(accountToDebitId); + final GLAccount accountToDebit = this.accountRepositoryWrapper.findOneWithNotFoundDetection(accountToDebitId); accountingRule.setAccountToDebit(accountToDebit); } if (accountToCreditId != null && changesOnly.containsKey(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue())) { - final GLAccount accountToCredit = accountRepositoryWrapper.findOneWithNotFoundDetection(accountToCreditId); + final GLAccount accountToCredit = this.accountRepositoryWrapper.findOneWithNotFoundDetection(accountToCreditId); accountingRule.setAccountToCredit(accountToCredit); } @@ -149,9 +181,33 @@ public class AccountingRuleWritePlatformServiceJpaRepositoryImpl implements Acco @Transactional @Override - public CommandProcessingResult deleteAccountingRule(Long accountingRuleId) { + public CommandProcessingResult deleteAccountingRule(final Long accountingRuleId) { final AccountingRule accountingRule = this.accountingRuleRepositoryWrapper.findOneWithNotFoundDetection(accountingRuleId); this.accountingRuleRepository.delete(accountingRule); 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 accountingTagRules = saveDebitOrCreditTags(creditOrDebitTagArray, transactionType); + } else { + throw new RuntimeException("Please Specify debitTags or accountToDebitId"); + } + return creditOrDebitAccount; + }*/ + + private List saveDebitOrCreditTags(final String[] creditOrDebitTagArray, final JournalEntryType transactionType, + final List accountingTagRules) { + for (final String creditOrDebitTag : creditOrDebitTagArray) { + final Long creditOrDebitTagIdLongValue = Long.valueOf(creditOrDebitTag); + final CodeValue creditOrDebitAccount = this.codeValueRepository.findOne(creditOrDebitTagIdLongValue); + final AccountingTagRule accountingTagRule = AccountingTagRule.create(creditOrDebitAccount, transactionType.getValue()); + accountingTagRules.add(accountingTagRule); + } + return accountingTagRules; + } }