Package org.mifosplatform.accounting.rule.service

Source Code of org.mifosplatform.accounting.rule.service.AccountingRuleWritePlatformServiceJpaRepositoryImpl

/**
* 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.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;
import org.mifosplatform.accounting.journalentry.domain.JournalEntryType;
import org.mifosplatform.accounting.rule.api.AccountingRuleJsonInputParams;
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;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
import org.mifosplatform.organisation.office.domain.Office;
import org.mifosplatform.organisation.office.domain.OfficeRepository;
import org.mifosplatform.organisation.office.exception.OfficeNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class AccountingRuleWritePlatformServiceJpaRepositoryImpl implements AccountingRuleWritePlatformService {

    private final static Logger logger = LoggerFactory.getLogger(AccountingRuleWritePlatformServiceJpaRepositoryImpl.class);

    private final AccountingRuleRepositoryWrapper accountingRuleRepositoryWrapper;
    private final AccountingRuleRepository accountingRuleRepository;
    private final GLAccountRepositoryWrapper accountRepositoryWrapper;
    private final OfficeRepository officeRepository;
    private final AccountingRuleCommandFromApiJsonDeserializer fromApiJsonDeserializer;
    private final CodeValueRepository codeValueRepository;

    @Autowired
    public AccountingRuleWritePlatformServiceJpaRepositoryImpl(final AccountingRuleRepositoryWrapper accountingRuleRepositoryWrapper,
            final GLAccountRepositoryWrapper accountRepositoryWrapper, final OfficeRepository officeRepository,
            final AccountingRuleRepository ruleRepository, final AccountingRuleCommandFromApiJsonDeserializer fromApiJsonDeserializer,
            final CodeValueRepository codeValueRepository) {
        this.accountRepositoryWrapper = accountRepositoryWrapper;
        this.officeRepository = officeRepository;
        this.accountingRuleRepository = ruleRepository;
        this.accountingRuleRepositoryWrapper = accountingRuleRepositoryWrapper;
        this.fromApiJsonDeserializer = fromApiJsonDeserializer;
        this.codeValueRepository = codeValueRepository;
    }

    /**
     * @param command
     * @param dve
     */
    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()));
        } 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",
                "Unknown data integrity issue with resource Accounting Rule: " + realCause.getMessage());
    }

    @Transactional
    @Override
    public CommandProcessingResult createAccountingRule(final JsonCommand command) {
        try {

            this.fromApiJsonDeserializer.validateForCreate(command.json());

            // check office is valid
            final Long officeId = command.longValueOfParameterNamed(GLClosureJsonInputParams.OFFICE_ID.getValue());
            Office office = null;
            if (officeId != null) {
                office = this.officeRepository.findOne(officeId);
                if (office == null) { throw new OfficeNotFoundException(officeId); }
            }

            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) {
            handleAccountingRuleIntegrityIssues(command, dve);
            return CommandProcessingResult.empty();
        }
    }

    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 Set<String> incomingDebitTags = debitTags == null ? new HashSet<String>() : new HashSet<>(Arrays.asList(debitTags));
        final Set<String> incomingCreditTags = creditTags == null ? new HashSet<String>() : new HashSet<>(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<>();

        if ((accountToDebitId != null && debitTags != null) || (accountToDebitId == null && debitTags == null)) {
            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(incomingDebitTags, JournalEntryType.DEBIT, accountingTagRules);
            allowMultipleDebitEntries = command
                    .booleanPrimitiveValueOfParameterNamed(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_DEBIT_ENTRIES.getValue());
        }

        if ((accountToCreditId != null && creditTags != null) || (accountToCreditId == null && creditTags == null)) {
            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(incomingCreditTags, JournalEntryType.CREDIT, accountingTagRules);
            allowMultipleCreditEntries = command
                    .booleanPrimitiveValueOfParameterNamed(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_CREDIT_ENTRIES.getValue());
        }

        final AccountingRule accountingRule = AccountingRule.fromJson(office, debitAccount, creditAccount, command,
                allowMultipleCreditEntries, allowMultipleDebitEntries);
        accountingRule.updateAccountingRuleForTags(accountingTagRules);

        return accountingRule;
    }

    @Transactional
    @Override
    public CommandProcessingResult updateAccountingRule(final Long accountingRuleId, final JsonCommand command) {

        try {

            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<>();
                    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<>();
                    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();
        }

    }

    private Set<String> determineCreditTagToAddAndRemoveOldTags(final String[] creditOrDebitTags, final JournalEntryType type,
            final AccountingRule accountingRule) {

        final Set<String> incomingTags = new HashSet<>(Arrays.asList(creditOrDebitTags));
        final Set<AccountingTagRule> existingTags = accountingRule.getAccountingTagRulesByType(type);
        final Set<String> existingTagIds = retrieveExistingTagIds(existingTags);
        final Set<String> tagsToAdd = new HashSet<>();
        final Set<String> tagsToRemove = existingTagIds;
        final Map<Long, AccountingTagRule> accountsToRemove = new HashMap<>();

        for (final String tagId : incomingTags) {
            if (existingTagIds.contains(tagId)) {
                tagsToRemove.remove(tagId);
            } else {
                tagsToAdd.add(tagId);
            }
        }

        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<>(accountsToRemove.values()));
        }
        return tagsToAdd;
    }

    private Set<String> retrieveExistingTagIds(final Set<AccountingTagRule> existingCreditTags) {
        final Set<String> existingCreditTagIds = new HashSet<>();
        for (final AccountingTagRule accountingTagRule : existingCreditTags) {
            existingCreditTagIds.add(accountingTagRule.getTagId().toString());
        }
        return existingCreditTagIds;
    }

    @Transactional
    @Override
    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 List<AccountingTagRule> saveDebitOrCreditTags(final Set<String> creditOrDebitTagArray, final JournalEntryType transactionType,
            final List<AccountingTagRule> accountingTagRules) {
        for (final String creditOrDebitTag : creditOrDebitTagArray) {
            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;
    }
}
TOP

Related Classes of org.mifosplatform.accounting.rule.service.AccountingRuleWritePlatformServiceJpaRepositoryImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.