From 5c38e151e88950ccdfc3d0a9740163e11a26d739 Mon Sep 17 00:00:00 2001 From: Vishwas Babu AJ Date: Tue, 27 Nov 2012 18:37:47 +0530 Subject: [PATCH] wip accounting service moving accounting wip code to new package --- .../patches/00001_accounting_tables.sql | 47 ++++++ .../api/ChartOfAccountsApiResource.java | 69 --------- .../api/commands/ChartOfAccountCommand.java | 78 ---------- .../api/data/ChartOfAccountsData.java | 24 ---- .../api/data/GeneralLedgerAccountData.java | 43 ------ .../AccountingApiDataConversionService.java | 9 -- .../AccountingApiJsonSerializerService.java | 11 -- ...ccountingApiDataConversionServiceImpl.java | 80 ----------- ...sonAccountingApiJsonSerializerService.java | 43 ------ .../accounting/domain/ChartOfAccounts.java | 92 ------------ .../domain/ChartOfAccountsRepository.java | 10 -- .../ChartOfAccountsReadPlatformService.java | 9 -- .../ChartOfAccountsWritePlatformService.java | 9 -- ...hartOfAccountsReadPlatformServiceImpl.java | 53 ------- ...WritePlatformServiceJpaRepositoryImpl.java | 40 ------ ...GsonPortfolioApiJsonSerializerService.java | 12 -- .../PortfolioApiJsonSerializerService.java | 4 - .../accounting/AccountingConstants.java | 15 ++ .../accounting/api/GLAccountsApiResource.java | 136 ++++++++++++++++++ .../accounting/api/GLClosuresApiResource.java | 128 +++++++++++++++++ .../api/commands/GLAccountCommand.java | 104 ++++++++++++++ .../api/commands/GLClosureCommand.java | 48 +++++++ .../accounting/api/data/GLAccountData.java | 42 ++++++ .../accounting/api/data/GLClosureData.java | 48 +++++++ .../AccountingApiDataConversionService.java | 12 ++ .../AccountingApiJsonSerializerService.java | 22 +++ ...ccountingApiDataConversionServiceImpl.java | 101 +++++++++++++ ...sonAccountingApiJsonSerializerService.java | 75 ++++++++++ .../accounting/domain/GLAccount.java | 116 +++++++++++++++ .../domain/GLAccountRepository.java | 8 ++ .../accounting/domain/GLClosure.java | 67 +++++++++ .../domain/GLClosureRepository.java | 8 ++ .../GLAccountDuplicateException.java | 15 ++ ...AccountInvalidClassificationException.java | 14 ++ .../GLAccountInvalidDeleteException.java | 26 ++++ .../GLAccountInvalidParentException.java | 15 ++ .../GLAccountNotFoundException.java | 13 ++ .../GLClosureDuplicateException.java | 17 +++ .../GLClosureNotFoundException.java | 14 ++ .../service/GLAccountCommandValidator.java | 63 ++++++++ .../service/GLAccountReadPlatformService.java | 13 ++ .../GLAccountWritePlatformService.java | 17 +++ .../service/GLClosureCommandValidator.java | 48 +++++++ .../service/GLClosureReadPlatformService.java | 13 ++ .../GLClosureWritePlatformService.java | 17 +++ .../GLAccountReadPlatformServiceImpl.java | 101 +++++++++++++ ...WritePlatformServiceJpaRepositoryImpl.java | 126 ++++++++++++++++ .../GLClosureReadPlatformServiceImpl.java | 92 ++++++++++++ ...WritePlatformServiceJpaRepositoryImpl.java | 103 +++++++++++++ .../user/command/RolePermissionCommand.java | 4 +- 50 files changed, 1686 insertions(+), 588 deletions(-) create mode 100755 mifosng-db/patches/00001_accounting_tables.sql delete mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/ChartOfAccountsApiResource.java delete mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/commands/ChartOfAccountCommand.java delete mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/data/ChartOfAccountsData.java delete mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/data/GeneralLedgerAccountData.java delete mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/infrastructure/AccountingApiDataConversionService.java delete mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/infrastructure/AccountingApiJsonSerializerService.java delete mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/infrastructure/impl/AccountingApiDataConversionServiceImpl.java delete mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/infrastructure/impl/GoogleGsonAccountingApiJsonSerializerService.java delete mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/accounting/domain/ChartOfAccounts.java delete mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/accounting/domain/ChartOfAccountsRepository.java delete mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/accounting/service/ChartOfAccountsReadPlatformService.java delete mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/accounting/service/ChartOfAccountsWritePlatformService.java delete mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/accounting/service/impl/ChartOfAccountsReadPlatformServiceImpl.java delete mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/accounting/service/impl/ChartOfAccountsWritePlatformServiceJpaRepositoryImpl.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/AccountingConstants.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/accounting/api/GLAccountsApiResource.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/api/GLClosuresApiResource.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/accounting/api/commands/GLAccountCommand.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/api/commands/GLClosureCommand.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/accounting/api/data/GLAccountData.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/api/data/GLClosureData.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/accounting/api/infrastructure/AccountingApiDataConversionService.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/accounting/api/infrastructure/AccountingApiJsonSerializerService.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/accounting/api/infrastructure/impl/AccountingApiDataConversionServiceImpl.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/accounting/api/infrastructure/impl/GoogleGsonAccountingApiJsonSerializerService.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/accounting/domain/GLAccount.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/accounting/domain/GLAccountRepository.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/domain/GLClosure.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/domain/GLClosureRepository.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountDuplicateException.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountInvalidClassificationException.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountInvalidDeleteException.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountInvalidParentException.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountNotFoundException.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLClosureDuplicateException.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLClosureNotFoundException.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLAccountCommandValidator.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLAccountReadPlatformService.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLAccountWritePlatformService.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLClosureCommandValidator.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLClosureReadPlatformService.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLClosureWritePlatformService.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLAccountReadPlatformServiceImpl.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLAccountWritePlatformServiceJpaRepositoryImpl.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLClosureReadPlatformServiceImpl.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLClosureWritePlatformServiceJpaRepositoryImpl.java diff --git a/mifosng-db/patches/00001_accounting_tables.sql b/mifosng-db/patches/00001_accounting_tables.sql new file mode 100755 index 000000000..3ec71c0d1 --- /dev/null +++ b/mifosng-db/patches/00001_accounting_tables.sql @@ -0,0 +1,47 @@ +DROP TABLE IF EXISTS `m_acc_coa`; + +CREATE TABLE `acc_gl_account` ( + `id` BIGINT(20) NOT NULL AUTO_INCREMENT, + `name` VARCHAR(45) NOT NULL, + `parent_id` BIGINT(20) NULL DEFAULT NULL, + `gl_code` VARCHAR(45) NOT NULL, + `disabled` TINYINT(1) NOT NULL DEFAULT '0', + `manual_journal_entries_allowed` TINYINT(1) NOT NULL DEFAULT '1', + `header_account` TINYINT(1) NOT NULL DEFAULT '0', + `classification` VARCHAR(45) NOT NULL, + `description` VARCHAR(500) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE INDEX `acc_gl_code` (`gl_code`), + INDEX `FK_ACC_0000000001` (`parent_id`), + CONSTRAINT `FK_ACC_0000000001` FOREIGN KEY (`parent_id`) REFERENCES `acc_gl_account` (`id`) +) +COLLATE='utf8_general_ci' +ENGINE=InnoDB; + +DROP TABLE IF EXISTS `acc_gl_closure`; + +CREATE TABLE `acc_gl_closure` ( + `id` BIGINT(20) NOT NULL AUTO_INCREMENT, + `office_id` BIGINT(20) NOT NULL, + `closing_date` DATE NOT NULL, + `is_deleted` INT(20) NOT NULL DEFAULT '0', + `createdby_id` BIGINT(20) NULL DEFAULT NULL, + `lastmodifiedby_id` BIGINT(20) NULL DEFAULT NULL, + `created_date` DATETIME NULL DEFAULT NULL, + `lastmodified_date` DATETIME NULL DEFAULT NULL, + `comments` VARCHAR(500) NULL DEFAULT NULL, + PRIMARY KEY (`id`), + INDEX `FK_acc_gl_closure_m_office` (`office_id`), + INDEX `FK_acc_gl_closure_m_appuser` (`createdby_id`), + INDEX `FK_acc_gl_closure_m_appuser_2` (`lastmodifiedby_id`), + UNIQUE INDEX `office_id_closing_date` (`office_id`, `closing_date`), + CONSTRAINT `FK_acc_gl_closure_m_appuser` FOREIGN KEY (`createdby_id`) REFERENCES `m_appuser` (`id`), + CONSTRAINT `FK_acc_gl_closure_m_appuser_2` FOREIGN KEY (`lastmodifiedby_id`) REFERENCES `m_appuser` (`id`), + CONSTRAINT `FK_acc_gl_closure_m_office` FOREIGN KEY (`office_id`) REFERENCES `m_office` (`id`) +) +COLLATE='utf8_general_ci' +ENGINE=InnoDB; + + + + diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/ChartOfAccountsApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/ChartOfAccountsApiResource.java deleted file mode 100644 index 476e4c8c8..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/ChartOfAccountsApiResource.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.mifosng.platform.accounting.api; - -import java.util.Set; - -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.UriInfo; - -import org.mifosng.platform.accounting.api.commands.ChartOfAccountCommand; -import org.mifosng.platform.accounting.api.data.ChartOfAccountsData; -import org.mifosng.platform.accounting.api.infrastructure.AccountingApiDataConversionService; -import org.mifosng.platform.accounting.service.ChartOfAccountsReadPlatformService; -import org.mifosng.platform.accounting.service.ChartOfAccountsWritePlatformService; -import org.mifosng.platform.api.data.EntityIdentifier; -import org.mifosng.platform.api.infrastructure.PortfolioApiJsonSerializerService; -import org.mifosng.platform.infrastructure.api.ApiParameterHelper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Component; - -@Path("/coa") -@Component -@Scope("singleton") -public class ChartOfAccountsApiResource { - - @Autowired - private ChartOfAccountsReadPlatformService coaReadPlatformService; - - @Autowired - private ChartOfAccountsWritePlatformService coaWritePlatformService; - - @Autowired - private AccountingApiDataConversionService apiDataConversionService; - - @Autowired - private PortfolioApiJsonSerializerService apiJsonSerializerService; - -// private final static Logger logger = LoggerFactory.getLogger(ChartOfAccountsApiResource.class); - - @GET - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) - public String retrieveExistingChartOfAccounts(@Context final UriInfo uriInfo) { - - final Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); - final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); - - final ChartOfAccountsData chartOfAccounts = this.coaReadPlatformService.retrieveChartOfAccounts(); - - return this.apiJsonSerializerService.serializeChartOfAccountDataToJson(prettyPrint, responseParameters, chartOfAccounts); - } - - @POST - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) - public String createChartOfAccounts(final String jsonRequestBody) { - - final ChartOfAccountCommand command = this.apiDataConversionService.convertJsonToChartOfAccountCommand(null, jsonRequestBody); - - final Long coaId = coaWritePlatformService.createAccount(command); - - return this.apiJsonSerializerService.serializeEntityIdentifier(new EntityIdentifier(coaId)); - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/commands/ChartOfAccountCommand.java b/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/commands/ChartOfAccountCommand.java deleted file mode 100644 index 80dbebbe1..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/commands/ChartOfAccountCommand.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.mifosng.platform.accounting.api.commands; - -import java.util.Set; - -/** - * Immutable command for adding an account to chart of accounts. - */ -public class ChartOfAccountCommand { - - private final Long id; - private final String name; - private final Long parentId; - private final String glCode; - private final Boolean disabled; - private final Boolean manualEntriesAllowed; - private final String category; - private final String ledgerType; - private final String description; - - private final Set requestParameters; - - public ChartOfAccountCommand(final Set modifiedParameters, - final Long id, final String name, - final Long parentId, final String glCode, final Boolean disabled, - final Boolean manualEntriesAllowed, final String category, - final String ledgerType, final String description) { - this.requestParameters = modifiedParameters; - this.id = id; - this.name = name; - this.parentId = parentId; - this.glCode = glCode; - this.disabled = disabled; - this.manualEntriesAllowed = manualEntriesAllowed; - this.category = category; - this.ledgerType = ledgerType; - this.description = description; - } - - public boolean isNamePassedOnRequest() { - return this.requestParameters.contains("name"); - } - - public Long getId() { - return id; - } - - public String getName() { - return name; - } - - public Long getParentId() { - return parentId; - } - - public String getGlCode() { - return glCode; - } - - public Boolean getDisabled() { - return disabled; - } - - public Boolean getManualEntriesAllowed() { - return manualEntriesAllowed; - } - - public String getCategory() { - return category; - } - - public String getLedgerType() { - return ledgerType; - } - - public String getDescription() { - return description; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/data/ChartOfAccountsData.java b/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/data/ChartOfAccountsData.java deleted file mode 100644 index 55afad28f..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/data/ChartOfAccountsData.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.mifosng.platform.accounting.api.data; - -import java.util.Collection; - -/** - * Immutable object representing chart of accounts data. - * - * Note: no getter/setters required as google-gson will produce json from fields of object. - */ -public class ChartOfAccountsData { - - @SuppressWarnings("unused") - private final Long id; - @SuppressWarnings("unused") - private final String name; - @SuppressWarnings("unused") - private final Collection accounts; - - public ChartOfAccountsData(final Long id, final String name, final Collection accounts) { - this.id = id; - this.name = name; - this.accounts = accounts; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/data/GeneralLedgerAccountData.java b/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/data/GeneralLedgerAccountData.java deleted file mode 100644 index 4c955db33..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/data/GeneralLedgerAccountData.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.mifosng.platform.accounting.api.data; - -/** - * Immutable object representing a general ledger accounts data as required by chart of accounts. - * - * Note: no getter/setters required as google-gson will produce json from fields of object. - */ -public class GeneralLedgerAccountData { - - @SuppressWarnings("unused") - private final Long id; - @SuppressWarnings("unused") - private final String name; - @SuppressWarnings("unused") - private final Long parentId; - @SuppressWarnings("unused") - private final String glCode; - @SuppressWarnings("unused") - private final boolean disabled; - @SuppressWarnings("unused") - private final boolean manualEntriesAllowed; - @SuppressWarnings("unused") - private final String category; - @SuppressWarnings("unused") - private final String ledgerType; - @SuppressWarnings("unused") - private final String description; - - public GeneralLedgerAccountData(final Long id, final String name, - final Long parentId, final String glCode, final boolean disabled, - final boolean manualEntriesAllowed, final String category, - final String ledgerType, final String description) { - this.id = id; - this.name = name; - this.parentId = parentId; - this.glCode = glCode; - this.disabled = disabled; - this.manualEntriesAllowed = manualEntriesAllowed; - this.category = category; - this.ledgerType = ledgerType; - this.description = description; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/infrastructure/AccountingApiDataConversionService.java b/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/infrastructure/AccountingApiDataConversionService.java deleted file mode 100644 index 23f81865a..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/infrastructure/AccountingApiDataConversionService.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.mifosng.platform.accounting.api.infrastructure; - -import org.mifosng.platform.accounting.api.commands.ChartOfAccountCommand; - -public interface AccountingApiDataConversionService { - - ChartOfAccountCommand convertJsonToChartOfAccountCommand(Long resourceIdentifier, String json); - -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/infrastructure/AccountingApiJsonSerializerService.java b/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/infrastructure/AccountingApiJsonSerializerService.java deleted file mode 100644 index 3b50de1ee..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/infrastructure/AccountingApiJsonSerializerService.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.mifosng.platform.accounting.api.infrastructure; - -import java.util.Set; - -import org.mifosng.platform.accounting.api.data.ChartOfAccountsData; - -public interface AccountingApiJsonSerializerService { - - String serializeChartOfAccountDataToJson(boolean prettyPrint, Set responseParameters, ChartOfAccountsData chartOfAccounts); - -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/infrastructure/impl/AccountingApiDataConversionServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/infrastructure/impl/AccountingApiDataConversionServiceImpl.java deleted file mode 100644 index e67203fc4..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/infrastructure/impl/AccountingApiDataConversionServiceImpl.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.mifosng.platform.accounting.api.infrastructure.impl; - -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.lang.StringUtils; -import org.mifosng.platform.accounting.api.commands.ChartOfAccountCommand; -import org.mifosng.platform.accounting.api.infrastructure.AccountingApiDataConversionService; -import org.mifosng.platform.infrastructure.api.JsonParserHelper; -import org.mifosng.platform.infrastructure.errorhandling.InvalidJsonException; -import org.mifosng.platform.infrastructure.errorhandling.UnsupportedParameterException; -import org.springframework.stereotype.Service; - -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; -import com.google.gson.reflect.TypeToken; - -/** - * Service specifically for converting JSON requests into command ojects for accounting API. - */ -@Service -public class AccountingApiDataConversionServiceImpl implements AccountingApiDataConversionService { - - private final Gson gsonConverter; - - public AccountingApiDataConversionServiceImpl() { - gsonConverter = new Gson(); - } - - private void checkForUnsupportedParameters(Map requestMap, Set supportedParams) { - List unsupportedParameterList = new ArrayList(); - for (String providedParameter : requestMap.keySet()) { - if (!supportedParams.contains(providedParameter)) { - unsupportedParameterList.add(providedParameter); - } - } - - if (!unsupportedParameterList.isEmpty()) { - throw new UnsupportedParameterException(unsupportedParameterList); - } - } - - @Override - public ChartOfAccountCommand convertJsonToChartOfAccountCommand(final Long resourceIdentifier, final String json) { - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>(){}.getType(); - final Map requestMap = gsonConverter.fromJson(json, typeOfMap); - - final Set supportedParams = new HashSet( - Arrays.asList("id", "name", "parentId", "glCode", "disabled", "manualEntriesAllowed", "category", "ledgerType", "description", "locale", "dateFormat") - ); - - checkForUnsupportedParameters(requestMap, supportedParams); - - final JsonParser parser = new JsonParser(); - final JsonElement element = parser.parse(json); - final JsonParserHelper helper = new JsonParserHelper(); - - final Set requestParamatersDetected = new HashSet(); - final String name = helper.extractStringNamed("name", element, requestParamatersDetected); - final Long parentId = helper.extractLongNamed("parentId", element, requestParamatersDetected); - final String glCode = helper.extractStringNamed("glCode", element, requestParamatersDetected); - final Boolean disabled = helper.extractBooleanNamed("disabled", element, requestParamatersDetected); - final Boolean manualEntriesAllowed = helper.extractBooleanNamed("manualEntriesAllowed", element, requestParamatersDetected); - final String category = helper.extractStringNamed("category", element, requestParamatersDetected); - final String ledgerType = helper.extractStringNamed("ledgerType", element, requestParamatersDetected); - final String description = helper.extractStringNamed("description", element, requestParamatersDetected); - - return new ChartOfAccountCommand(requestParamatersDetected, resourceIdentifier, name, parentId, glCode, disabled, manualEntriesAllowed, category, ledgerType, description); - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/infrastructure/impl/GoogleGsonAccountingApiJsonSerializerService.java b/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/infrastructure/impl/GoogleGsonAccountingApiJsonSerializerService.java deleted file mode 100644 index f121b93a6..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/api/infrastructure/impl/GoogleGsonAccountingApiJsonSerializerService.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.mifosng.platform.accounting.api.infrastructure.impl; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -import org.mifosng.platform.accounting.api.data.ChartOfAccountsData; -import org.mifosng.platform.accounting.api.infrastructure.AccountingApiJsonSerializerService; -import org.mifosng.platform.api.infrastructure.PortfolioApiJsonSerializerService; -import org.mifosng.platform.infrastructure.api.GoogleGsonSerializerHelper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.google.gson.Gson; - -/** - * Implementation of {@link PortfolioApiJsonSerializerService} that uses google-gson to - * serialize Java object representation into JSON. - */ -@Service -public class GoogleGsonAccountingApiJsonSerializerService implements AccountingApiJsonSerializerService { - - private static final Set CHART_OF_ACCOUNTS_DATA_PARAMETERS = new HashSet(Arrays.asList("id", "name")); - - private final GoogleGsonSerializerHelper helper; - - @Autowired - public GoogleGsonAccountingApiJsonSerializerService( - final GoogleGsonSerializerHelper helper) { - this.helper = helper; - } - - @Override - public String serializeChartOfAccountDataToJson(final boolean prettyPrint, - final Set responseParameters, - final ChartOfAccountsData chartOfAccounts) { - final Gson gsonDeserializer = helper - .createGsonBuilderWithParameterExclusionSerializationStrategy( - CHART_OF_ACCOUNTS_DATA_PARAMETERS, prettyPrint, - responseParameters); - return helper.serializedJsonFrom(gsonDeserializer, chartOfAccounts); - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/domain/ChartOfAccounts.java b/mifosng-provider/src/main/java/org/mifosng/platform/accounting/domain/ChartOfAccounts.java deleted file mode 100644 index 4766c91b6..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/domain/ChartOfAccounts.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.mifosng.platform.accounting.domain; - -import java.util.LinkedList; -import java.util.List; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -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.springframework.data.jpa.domain.AbstractPersistable; - -@Entity -@Table(name = "m_acc_coa", uniqueConstraints={@UniqueConstraint(columnNames = {"gl_code"}, name="acc_gl_code")}) -public class ChartOfAccounts extends AbstractPersistable { - - @OneToMany(fetch = FetchType.EAGER) - @JoinColumn(name = "parent_id") - private final List children = new LinkedList(); - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "parent_id") - private ChartOfAccounts parent; - - @SuppressWarnings("unused") - @Column(name = "name", nullable = false, length=45) - private String name; - - @SuppressWarnings("unused") - @Column(name = "gl_code", nullable = false, length=100) - private String glCode; - - @SuppressWarnings("unused") - @Column(name = "is_disabled", nullable=false) - private boolean disabed = false; - - @SuppressWarnings("unused") - @Column(name = "manual_entries_allowed", nullable=false) - private boolean manualEntriesAllowed = true; - - @SuppressWarnings("unused") - @Column(name = "category", nullable = false, length=45) - private String category; - - @SuppressWarnings("unused") - @Column(name = "ledger_type", nullable = false, length=45) - private String ledgerType; - - @SuppressWarnings("unused") - @Column(name = "description", nullable = false, length=500) - private String description; - - public static ChartOfAccounts rootAccount(final String name) { - return new ChartOfAccounts(null, name); - } - - public static ChartOfAccounts createNew(final ChartOfAccounts parent, final String name) { - return new ChartOfAccounts(parent, name); - } - - protected ChartOfAccounts() { - // - } - - private ChartOfAccounts(final ChartOfAccounts parent, final String name) { - this.parent = parent; - if (parent != null) { - this.parent.addChild(this); - } - - if (StringUtils.isNotBlank(name)) { - this.name = name.trim(); - } else { - this.name = null; - } - this.glCode = "TEST-1"; - this.disabed = false; - this.manualEntriesAllowed = true; - this.category = "ASSETS"; - this.ledgerType = "HEADER"; - this.description = "Some description value.."; - } - - private void addChild(final ChartOfAccounts coa) { - this.children.add(coa); - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/domain/ChartOfAccountsRepository.java b/mifosng-provider/src/main/java/org/mifosng/platform/accounting/domain/ChartOfAccountsRepository.java deleted file mode 100644 index f8fa05b90..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/domain/ChartOfAccountsRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.mifosng.platform.accounting.domain; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.JpaSpecificationExecutor; - -public interface ChartOfAccountsRepository extends - JpaRepository, - JpaSpecificationExecutor { - // no added behaviour -} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/service/ChartOfAccountsReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/accounting/service/ChartOfAccountsReadPlatformService.java deleted file mode 100644 index eec37f5ab..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/service/ChartOfAccountsReadPlatformService.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.mifosng.platform.accounting.service; - -import org.mifosng.platform.accounting.api.data.ChartOfAccountsData; - -public interface ChartOfAccountsReadPlatformService { - - ChartOfAccountsData retrieveChartOfAccounts(); - -} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/service/ChartOfAccountsWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/accounting/service/ChartOfAccountsWritePlatformService.java deleted file mode 100644 index a24e1b6d0..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/service/ChartOfAccountsWritePlatformService.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.mifosng.platform.accounting.service; - -import org.mifosng.platform.accounting.api.commands.ChartOfAccountCommand; - -public interface ChartOfAccountsWritePlatformService { - - Long createAccount(ChartOfAccountCommand command); - -} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/service/impl/ChartOfAccountsReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/accounting/service/impl/ChartOfAccountsReadPlatformServiceImpl.java deleted file mode 100644 index 3d6701cf3..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/service/impl/ChartOfAccountsReadPlatformServiceImpl.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.mifosng.platform.accounting.service.impl; - -import java.util.Arrays; -import java.util.Collection; - -import org.mifosng.platform.accounting.api.data.ChartOfAccountsData; -import org.mifosng.platform.accounting.api.data.GeneralLedgerAccountData; -import org.mifosng.platform.accounting.service.ChartOfAccountsReadPlatformService; -import org.mifosng.platform.infrastructure.TenantAwareRoutingDataSource; -import org.mifosng.platform.security.PlatformSecurityContext; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Service; - -@Service -public class ChartOfAccountsReadPlatformServiceImpl implements ChartOfAccountsReadPlatformService { - - @SuppressWarnings("unused") - private final JdbcTemplate jdbcTemplate; - @SuppressWarnings("unused") - private final PlatformSecurityContext context; - - @Autowired - public ChartOfAccountsReadPlatformServiceImpl( - final PlatformSecurityContext context, - final TenantAwareRoutingDataSource dataSource) { - this.context = context; - this.jdbcTemplate = new JdbcTemplate(dataSource); - } - - @Override - public ChartOfAccountsData retrieveChartOfAccounts() { - // FIXME - KW - just stubbing impl for now. - - boolean isLedgerAccountDisabled = false; - boolean isManualEntriesAllowed = true; - - final String assetsGlCode = "1"; - final String category = "ASSETS"; - final Long parentId = null; - final String generalLedgerName = "Assets"; - final String ledgerType = "HEADER"; - final String description = "Some descriptoin of the general ledger accounts purpose."; - - GeneralLedgerAccountData assetsHeader = new GeneralLedgerAccountData(Long.valueOf(1), generalLedgerName, parentId, assetsGlCode, isLedgerAccountDisabled, isManualEntriesAllowed, category, ledgerType, description); - - GeneralLedgerAccountData liabilitiesHeader = new GeneralLedgerAccountData(Long.valueOf(1), "Liabilities", parentId, "2", isLedgerAccountDisabled, isManualEntriesAllowed, "LIABILITIES", ledgerType, description); - - Collection accounts = Arrays.asList(assetsHeader, liabilitiesHeader); - - return new ChartOfAccountsData(Long.valueOf(1), "Default Chart of Accounts", accounts); - } -} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/service/impl/ChartOfAccountsWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/accounting/service/impl/ChartOfAccountsWritePlatformServiceJpaRepositoryImpl.java deleted file mode 100644 index 35125a2c5..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/accounting/service/impl/ChartOfAccountsWritePlatformServiceJpaRepositoryImpl.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.mifosng.platform.accounting.service.impl; - -import org.mifosng.platform.accounting.api.commands.ChartOfAccountCommand; -import org.mifosng.platform.accounting.domain.ChartOfAccounts; -import org.mifosng.platform.accounting.domain.ChartOfAccountsRepository; -import org.mifosng.platform.accounting.service.ChartOfAccountsWritePlatformService; -import org.mifosng.platform.security.PlatformSecurityContext; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -public class ChartOfAccountsWritePlatformServiceJpaRepositoryImpl implements ChartOfAccountsWritePlatformService { - -// private final static Logger logger = LoggerFactory.getLogger(ChartOfAccountsWritePlatformServiceJpaRepositoryImpl.class); - - private final PlatformSecurityContext context; - private final ChartOfAccountsRepository chartOfAccountsRepository; - - @Autowired - public ChartOfAccountsWritePlatformServiceJpaRepositoryImpl( - final PlatformSecurityContext context, - final ChartOfAccountsRepository chartOfAccountsRepository) { - this.context = context; - this.chartOfAccountsRepository = chartOfAccountsRepository; - } - - @Transactional - @Override - public Long createAccount(final ChartOfAccountCommand command) { - - context.authenticatedUser(); - - final ChartOfAccounts entity = ChartOfAccounts.createNew(null, command.getName()); - - this.chartOfAccountsRepository.save(entity); - - return entity.getId(); - } -} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/GoogleGsonPortfolioApiJsonSerializerService.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/GoogleGsonPortfolioApiJsonSerializerService.java index af7d5251d..0866732d0 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/GoogleGsonPortfolioApiJsonSerializerService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/GoogleGsonPortfolioApiJsonSerializerService.java @@ -5,7 +5,6 @@ import java.util.Collection; import java.util.HashSet; import java.util.Set; -import org.mifosng.platform.accounting.api.data.ChartOfAccountsData; import org.mifosng.platform.api.commands.ClientCommand; import org.mifosng.platform.api.data.ChargeData; import org.mifosng.platform.api.data.ClientAccountSummaryCollectionData; @@ -172,9 +171,6 @@ public class GoogleGsonPortfolioApiJsonSerializerService implements PortfolioApi "firstname", "lastname", "addressLine1", "addressLine2", "city", "state", "zip", "country", "mobileNumber", "housePhoneNumber", "comment", "dob")); - // accounting - private static final Set CHART_OF_ACCOUNTS_DATA_PARAMETERS = new HashSet(Arrays.asList("id", "name")); - private final GoogleGsonSerializerHelper helper; @Autowired @@ -577,14 +573,6 @@ public class GoogleGsonPortfolioApiJsonSerializerService implements PortfolioApi return helper.serializedJsonFrom(gsonDeserializer, accounts.toArray(new SavingAccountData[accounts.size()])); } - @Override - public String serializeChartOfAccountDataToJson(final boolean prettyPrint, final Set responseParameters, - final ChartOfAccountsData chartOfAccounts) { - final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy( - CHART_OF_ACCOUNTS_DATA_PARAMETERS, prettyPrint, responseParameters); - return helper.serializedJsonFrom(gsonDeserializer, chartOfAccounts); - } - @Override public String serializeGuarantorDataToJson(boolean prettyPrint, Set responseParameters, GuarantorData guarantorData) { final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(GUARANTOR_DATA_PARAMETERS, diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiJsonSerializerService.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiJsonSerializerService.java index b495a36ca..8a2f678fc 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiJsonSerializerService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/PortfolioApiJsonSerializerService.java @@ -3,7 +3,6 @@ package org.mifosng.platform.api.infrastructure; import java.util.Collection; import java.util.Set; -import org.mifosng.platform.accounting.api.data.ChartOfAccountsData; import org.mifosng.platform.api.commands.ClientCommand; import org.mifosng.platform.api.data.ChargeData; import org.mifosng.platform.api.data.ClientAccountSummaryCollectionData; @@ -156,7 +155,4 @@ public interface PortfolioApiJsonSerializerService { String serializeGuarantorDataToJson(boolean prettyPrint, Set responseParameters, GuarantorData guarantorData); - // TODO - KW - might devide serialize up into portfolio and account to - // reduce interface - String serializeChartOfAccountDataToJson(boolean prettyPrint, Set responseParameters, ChartOfAccountsData chartOfAccounts); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/AccountingConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/AccountingConstants.java new file mode 100755 index 000000000..78c396dce --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/AccountingConstants.java @@ -0,0 +1,15 @@ +package org.mifosplatform.accounting; + +public class AccountingConstants { + + /*** Categories for Accounting **/ + public static enum GL_ACCOUNT_CLASSIFICATION { + ASSETS, LIABILITIES, INCOME, EXPENDITURE, EQUITY; + + @Override + public String toString() { + return name().toString(); + } + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/GLAccountsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/GLAccountsApiResource.java new file mode 100644 index 000000000..4c084b053 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/GLAccountsApiResource.java @@ -0,0 +1,136 @@ +package org.mifosplatform.accounting.api; + +import java.util.List; +import java.util.Set; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +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.Response; +import javax.ws.rs.core.UriInfo; + +import org.mifosng.platform.api.data.EntityIdentifier; +import org.mifosng.platform.infrastructure.api.ApiParameterHelper; +import org.mifosng.platform.security.PlatformSecurityContext; +import org.mifosplatform.accounting.api.commands.GLAccountCommand; +import org.mifosplatform.accounting.api.data.GLAccountData; +import org.mifosplatform.accounting.api.infrastructure.AccountingApiDataConversionService; +import org.mifosplatform.accounting.api.infrastructure.AccountingApiJsonSerializerService; +import org.mifosplatform.accounting.service.GLAccountReadPlatformService; +import org.mifosplatform.accounting.service.GLAccountWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +@Path("/glaccounts") +@Component +@Scope("singleton") +public class GLAccountsApiResource { + + @Autowired + private GLAccountReadPlatformService glAccountReadPlatformService; + + @Autowired + private GLAccountWritePlatformService glAccountWritePlatformService; + + @Autowired + private AccountingApiDataConversionService accountingApiDataConversionService; + + @Autowired + private AccountingApiJsonSerializerService apiJsonSerializerService; + + private final String entityType = "GL_ACCOUNT"; + + @Autowired + private PlatformSecurityContext context; + + // private final static Logger logger = + // LoggerFactory.getLogger(GLAccountsApiResource.class); + + /** + * @param uriInfo + * @param classification + * @param searchParam + * Option param to search by "Name" or "GL CODE" fragments + * @return + */ + @GET + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveAllAccounts(@Context final UriInfo uriInfo, @QueryParam("classification") final String classification, + @QueryParam("searchParam") final String searchParam) { + + context.authenticatedUser().validateHasReadPermission(entityType); + + final Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); + final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); + + final List glAccountDatas = this.glAccountReadPlatformService.retrieveAllGLAccounts(classification, searchParam); + + return this.apiJsonSerializerService.serializeGLAccountDataToJson(prettyPrint, responseParameters, glAccountDatas); + } + + @GET + @Path("{glAccountId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retreiveAccount(@PathParam("glAccountId") final Long glAccountId, @Context final UriInfo uriInfo) { + + context.authenticatedUser().validateHasReadPermission(entityType); + + final Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); + final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); + boolean template = ApiParameterHelper.template(uriInfo.getQueryParameters()); + + final GLAccountData glAccountData = this.glAccountReadPlatformService.retrieveGLAccountById(glAccountId); + if (template) { + // TODO: define templates + } + + return this.apiJsonSerializerService.serializeGLAccountDataToJson(prettyPrint, responseParameters, glAccountData); + } + + @POST + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String createGLAccount(final String jsonRequestBody) { + + final GLAccountCommand command = this.accountingApiDataConversionService.convertJsonToGLAccountCommand(null, jsonRequestBody); + + final Long coaId = glAccountWritePlatformService.createGLAccount(command); + + return this.apiJsonSerializerService.serializeEntityIdentifier(new EntityIdentifier(coaId)); + } + + @PUT + @Path("{glAccountId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String updateGLAccount(@PathParam("glAccountId") final Long glAccountId, final String jsonRequestBody) { + + final GLAccountCommand command = this.accountingApiDataConversionService.convertJsonToGLAccountCommand(null, jsonRequestBody); + + final Long coaId = glAccountWritePlatformService.updateGLAccount(glAccountId, command); + + return this.apiJsonSerializerService.serializeEntityIdentifier(new EntityIdentifier(coaId)); + } + + @DELETE + @Path("{glAccountId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response deleteGLAccount(@PathParam("glAccountId") final Long glAccountId) { + + this.glAccountWritePlatformService.deleteGLAccount(glAccountId); + + return Response.ok(new EntityIdentifier(glAccountId)).build(); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/GLClosuresApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/GLClosuresApiResource.java new file mode 100755 index 000000000..ebb3bbf4a --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/GLClosuresApiResource.java @@ -0,0 +1,128 @@ +package org.mifosplatform.accounting.api; + +import java.util.List; +import java.util.Set; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +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.Response; +import javax.ws.rs.core.UriInfo; + +import org.mifosng.platform.api.data.EntityIdentifier; +import org.mifosng.platform.infrastructure.api.ApiParameterHelper; +import org.mifosng.platform.security.PlatformSecurityContext; +import org.mifosplatform.accounting.api.commands.GLClosureCommand; +import org.mifosplatform.accounting.api.data.GLClosureData; +import org.mifosplatform.accounting.api.infrastructure.AccountingApiDataConversionService; +import org.mifosplatform.accounting.api.infrastructure.AccountingApiJsonSerializerService; +import org.mifosplatform.accounting.service.GLClosureReadPlatformService; +import org.mifosplatform.accounting.service.GLClosureWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +@Path("/glclosures") +@Component +@Scope("singleton") +public class GLClosuresApiResource { + + @Autowired + private GLClosureReadPlatformService glClosureReadPlatformService; + + @Autowired + private GLClosureWritePlatformService glClosureWritePlatformService; + + @Autowired + private AccountingApiDataConversionService accountingApiDataConversionService; + + @Autowired + private AccountingApiJsonSerializerService apiJsonSerializerService; + + private final String entityType = "GL_CLOSURE"; + + @Autowired + private PlatformSecurityContext context; + + // private final static Logger logger = + // LoggerFactory.getLogger(GLClosuresApiResource.class); + + @GET + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveAllClosures(@Context final UriInfo uriInfo, @QueryParam("officeId") final Long officeId) { + + context.authenticatedUser().validateHasReadPermission(entityType); + + final Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); + final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); + + final List glClosureDatas = this.glClosureReadPlatformService.retrieveAllGLClosures(officeId); + + return this.apiJsonSerializerService.serializeGLClosureDataToJson(prettyPrint, responseParameters, glClosureDatas); + } + + @GET + @Path("{glClosureId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retreiveClosure(@PathParam("glClosureId") final Long glClosureId, @Context final UriInfo uriInfo) { + + context.authenticatedUser().validateHasReadPermission(entityType); + + final Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); + final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); + boolean template = ApiParameterHelper.template(uriInfo.getQueryParameters()); + + final GLClosureData glClosureData = this.glClosureReadPlatformService.retrieveGLClosureById(glClosureId); + if (template) { + // TODO: define templates + } + + return this.apiJsonSerializerService.serializeGLClosureDataToJson(prettyPrint, responseParameters, glClosureData); + } + + @POST + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String createGLClosure(final String jsonRequestBody) { + + final GLClosureCommand command = this.accountingApiDataConversionService.convertJsonToGLClosureCommand(null, jsonRequestBody); + + final Long coaId = glClosureWritePlatformService.createGLClosure(command); + + return this.apiJsonSerializerService.serializeEntityIdentifier(new EntityIdentifier(coaId)); + } + + @PUT + @Path("{glClosureId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String updateGLClosure(@PathParam("glClosureId") final Long glClosureId, final String jsonRequestBody) { + + final GLClosureCommand command = this.accountingApiDataConversionService.convertJsonToGLClosureCommand(null, jsonRequestBody); + + final Long coaId = glClosureWritePlatformService.updateGLClosure(glClosureId, command); + + return this.apiJsonSerializerService.serializeEntityIdentifier(new EntityIdentifier(coaId)); + } + + @DELETE + @Path("{glClosureId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response deleteGLClosure(@PathParam("glClosureId") final Long glClosureId) { + + this.glClosureWritePlatformService.deleteGLClosure(glClosureId); + + return Response.ok(new EntityIdentifier(glClosureId)).build(); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/commands/GLAccountCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/commands/GLAccountCommand.java new file mode 100644 index 000000000..fbc1d0879 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/commands/GLAccountCommand.java @@ -0,0 +1,104 @@ +package org.mifosplatform.accounting.api.commands; + +import java.util.Set; + +/** + * Immutable command for adding a general Ledger Account + */ +public class GLAccountCommand { + + private final Long id; + private final String name; + private final Long parentId; + private final String glCode; + private final Boolean disabled; + private final Boolean manualEntriesAllowed; + private final Boolean headerAccount; + private final String classification; + private final String description; + + private final Set parametersPassedInRequest; + + public GLAccountCommand(final Set modifiedParameters, final Long id, final String name, final Long parentId, + final String glCode, final Boolean disabled, final Boolean manualEntriesAllowed, final String classification, + final Boolean headerAccount, final String description) { + this.parametersPassedInRequest = modifiedParameters; + this.id = id; + this.name = name; + this.parentId = parentId; + this.glCode = glCode; + this.disabled = disabled; + this.manualEntriesAllowed = manualEntriesAllowed; + this.classification = classification; + this.headerAccount = headerAccount; + this.description = description; + } + + public boolean isNameChanged() { + return this.parametersPassedInRequest.contains("name"); + } + + public boolean isParentIdChanged() { + return this.parametersPassedInRequest.contains("parentId"); + } + + public boolean isGLCodeChanged() { + return this.parametersPassedInRequest.contains("glCode"); + } + + public boolean isDisabledFlagChanged() { + return this.parametersPassedInRequest.contains("disabled"); + } + + public boolean isManualEntriesAllowedFlagChanged() { + return this.parametersPassedInRequest.contains("manualEntriesAllowed"); + } + + public boolean isClassificationChanged() { + return this.parametersPassedInRequest.contains("classification"); + } + + public boolean isHeaderAccountFlagChanged() { + return this.parametersPassedInRequest.contains("headerAccount"); + } + + public boolean isDescriptionChanged() { + return this.parametersPassedInRequest.contains("description"); + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public Long getParentId() { + return parentId; + } + + public String getGlCode() { + return glCode; + } + + public Boolean getDisabled() { + return disabled; + } + + public Boolean getManualEntriesAllowed() { + return manualEntriesAllowed; + } + + public Boolean getHeaderAccount() { + return headerAccount; + } + + public String getDescription() { + return description; + } + + public String getClassification() { + return classification; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/commands/GLClosureCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/commands/GLClosureCommand.java new file mode 100755 index 000000000..d7ff65837 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/commands/GLClosureCommand.java @@ -0,0 +1,48 @@ +package org.mifosplatform.accounting.api.commands; + +import java.util.Set; + +import org.joda.time.LocalDate; + +/** + * Immutable command for adding an accounting closure + */ +public class GLClosureCommand { + + private final Long id; + private final Long officeId; + private final LocalDate closingDate; + private final String comments; + + private final Set parametersPassedInRequest; + + public GLClosureCommand(final Set modifiedParameters, final Long id, final Long officeId, final LocalDate closingDate, + final String comments) { + this.id = id; + this.officeId = officeId; + this.closingDate = closingDate; + this.comments = comments; + this.parametersPassedInRequest = modifiedParameters; + } + + public boolean isCommentsChanged() { + return this.parametersPassedInRequest.contains("comments"); + } + + public Long getId() { + return this.id; + } + + public Long getOfficeId() { + return this.officeId; + } + + public LocalDate getClosingDate() { + return this.closingDate; + } + + public String getComments() { + return this.comments; + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/data/GLAccountData.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/data/GLAccountData.java new file mode 100644 index 000000000..d2a5e7b5a --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/data/GLAccountData.java @@ -0,0 +1,42 @@ +package org.mifosplatform.accounting.api.data; + +/** + * Immutable object representing a General Ledger Account + * + * Note: no getter/setters required as google-gson will produce json from fields + * of object. + */ +public class GLAccountData { + + @SuppressWarnings("unused") + private final Long id; + @SuppressWarnings("unused") + private final String name; + @SuppressWarnings("unused") + private final Long parentId; + @SuppressWarnings("unused") + private final String glCode; + @SuppressWarnings("unused") + private final boolean disabled; + @SuppressWarnings("unused") + private final boolean manualEntriesAllowed; + @SuppressWarnings("unused") + private final String classification; + @SuppressWarnings("unused") + private final Boolean headerAccount; + @SuppressWarnings("unused") + private final String description; + + public GLAccountData(final Long id, final String name, final Long parentId, final String glCode, final boolean disabled, + final boolean manualEntriesAllowed, final String classification, final boolean headerAccount, final String description) { + this.id = id; + this.name = name; + this.parentId = parentId; + this.glCode = glCode; + this.disabled = disabled; + this.manualEntriesAllowed = manualEntriesAllowed; + this.classification = classification; + this.headerAccount = headerAccount; + this.description = description; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/data/GLClosureData.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/data/GLClosureData.java new file mode 100755 index 000000000..c70b156f3 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/data/GLClosureData.java @@ -0,0 +1,48 @@ +package org.mifosplatform.accounting.api.data; + +import org.joda.time.LocalDate; + +/** + * Immutable object representing a General Ledger Account + * + * Note: no getter/setters required as google-gson will produce json from fields + * of object. + */ +public class GLClosureData { + + @SuppressWarnings("unused") + private final Long id; + @SuppressWarnings("unused") + private final Long officeId; + @SuppressWarnings("unused") + private final String officeName; + @SuppressWarnings("unused") + private final LocalDate closingDate; + @SuppressWarnings("unused") + private final boolean deleted; + @SuppressWarnings("unused") + private final LocalDate createdDate; + @SuppressWarnings("unused") + private final LocalDate lastUpdatedDate; + @SuppressWarnings("unused") + private final Long creatingByUserId; + @SuppressWarnings("unused") + private final Long lastUpdatedByUserId; + @SuppressWarnings("unused") + private final String comments; + + public GLClosureData(Long id, Long officeId, String officeName, LocalDate closingDate, boolean deleted, LocalDate createdDate, + LocalDate lastUpdatedDate, Long creatingByUserId, Long lastUpdatedByUserId, String comments) { + this.id = id; + this.officeId = officeId; + this.officeName = officeName; + this.closingDate = closingDate; + this.deleted = deleted; + this.createdDate = createdDate; + this.lastUpdatedDate = lastUpdatedDate; + this.creatingByUserId = creatingByUserId; + this.lastUpdatedByUserId = lastUpdatedByUserId; + this.comments = comments; + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/infrastructure/AccountingApiDataConversionService.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/infrastructure/AccountingApiDataConversionService.java new file mode 100644 index 000000000..63d8f9020 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/infrastructure/AccountingApiDataConversionService.java @@ -0,0 +1,12 @@ +package org.mifosplatform.accounting.api.infrastructure; + +import org.mifosplatform.accounting.api.commands.GLAccountCommand; +import org.mifosplatform.accounting.api.commands.GLClosureCommand; + +public interface AccountingApiDataConversionService { + + GLAccountCommand convertJsonToGLAccountCommand(Long resourceIdentifier, String json); + + GLClosureCommand convertJsonToGLClosureCommand(Long resourceIdentifier, String json); + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/infrastructure/AccountingApiJsonSerializerService.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/infrastructure/AccountingApiJsonSerializerService.java new file mode 100644 index 000000000..4e1dc7dc2 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/infrastructure/AccountingApiJsonSerializerService.java @@ -0,0 +1,22 @@ +package org.mifosplatform.accounting.api.infrastructure; + +import java.util.Collection; +import java.util.Set; + +import org.mifosng.platform.api.data.EntityIdentifier; +import org.mifosplatform.accounting.api.data.GLAccountData; +import org.mifosplatform.accounting.api.data.GLClosureData; + +public interface AccountingApiJsonSerializerService { + + String serializeEntityIdentifier(final EntityIdentifier identifier); + + String serializeGLAccountDataToJson(boolean prettyPrint, Set responseParameters, GLAccountData accountData); + + String serializeGLAccountDataToJson(boolean prettyPrint, Set responseParameters, Collection accountDatas); + + String serializeGLClosureDataToJson(boolean prettyPrint, Set responseParameters, GLClosureData closureData); + + String serializeGLClosureDataToJson(boolean prettyPrint, Set responseParameters, Collection closureDatas); + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/infrastructure/impl/AccountingApiDataConversionServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/infrastructure/impl/AccountingApiDataConversionServiceImpl.java new file mode 100644 index 000000000..cedee4746 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/infrastructure/impl/AccountingApiDataConversionServiceImpl.java @@ -0,0 +1,101 @@ +package org.mifosplatform.accounting.api.infrastructure.impl; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang.StringUtils; +import org.joda.time.LocalDate; +import org.mifosng.platform.infrastructure.api.JsonParserHelper; +import org.mifosng.platform.infrastructure.errorhandling.InvalidJsonException; +import org.mifosng.platform.infrastructure.errorhandling.UnsupportedParameterException; +import org.mifosplatform.accounting.api.commands.GLAccountCommand; +import org.mifosplatform.accounting.api.commands.GLClosureCommand; +import org.mifosplatform.accounting.api.infrastructure.AccountingApiDataConversionService; +import org.springframework.stereotype.Service; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; + +/** + * Service specifically for converting JSON requests into command objects for + * accounting API. + */ +@Service +public class AccountingApiDataConversionServiceImpl implements AccountingApiDataConversionService { + + private final Gson gsonConverter; + + public AccountingApiDataConversionServiceImpl() { + gsonConverter = new Gson(); + } + + private void checkForUnsupportedParameters(Map requestMap, Set supportedParams) { + List unsupportedParameterList = new ArrayList(); + for (String providedParameter : requestMap.keySet()) { + if (!supportedParams.contains(providedParameter)) { + unsupportedParameterList.add(providedParameter); + } + } + + if (!unsupportedParameterList.isEmpty()) { throw new UnsupportedParameterException(unsupportedParameterList); } + } + + @Override + public GLAccountCommand convertJsonToGLAccountCommand(final Long resourceIdentifier, final String json) { + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } + + final Type typeOfMap = new TypeToken>() {}.getType(); + final Map requestMap = gsonConverter.fromJson(json, typeOfMap); + + final Set supportedParams = new HashSet(Arrays.asList("name", "parentId", "glCode", "disabled", + "manualEntriesAllowed", "classification", "headerAccount", "description", "locale", "dateFormat")); + + checkForUnsupportedParameters(requestMap, supportedParams); + + final JsonParser parser = new JsonParser(); + final JsonElement element = parser.parse(json); + final JsonParserHelper helper = new JsonParserHelper(); + + final Set requestParamatersDetected = new HashSet(); + final String name = helper.extractStringNamed("name", element, requestParamatersDetected); + final Long parentId = helper.extractLongNamed("parentId", element, requestParamatersDetected); + final String glCode = helper.extractStringNamed("glCode", element, requestParamatersDetected); + final Boolean disabled = helper.extractBooleanNamed("disabled", element, requestParamatersDetected); + final Boolean manualEntriesAllowed = helper.extractBooleanNamed("manualEntriesAllowed", element, requestParamatersDetected); + final String category = helper.extractStringNamed("category", element, requestParamatersDetected); + final Boolean headerAccount = helper.extractBooleanNamed("headerAccount", element, requestParamatersDetected); + final String description = helper.extractStringNamed("description", element, requestParamatersDetected); + + return new GLAccountCommand(requestParamatersDetected, resourceIdentifier, name, parentId, glCode, disabled, manualEntriesAllowed, + category, headerAccount, description); + } + + @Override + public GLClosureCommand convertJsonToGLClosureCommand(Long resourceIdentifier, String json) { + final Type typeOfMap = new TypeToken>() {}.getType(); + final Map requestMap = gsonConverter.fromJson(json, typeOfMap); + + final Set supportedParams = new HashSet( + Arrays.asList("officeId", "closingDate", "comments", "locale", "dateFormat")); + + checkForUnsupportedParameters(requestMap, supportedParams); + + final JsonParser parser = new JsonParser(); + final JsonElement element = parser.parse(json); + final JsonParserHelper helper = new JsonParserHelper(); + + final Set requestParamatersDetected = new HashSet(); + final Long officeId = helper.extractLongNamed("officeId", element, requestParamatersDetected); + final String comments = helper.extractStringNamed("comments", element, requestParamatersDetected); + final LocalDate closingDate = helper.extractLocalDateNamed("closingDate", element, requestParamatersDetected); + + return new GLClosureCommand(requestParamatersDetected, resourceIdentifier, officeId, closingDate, comments); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/infrastructure/impl/GoogleGsonAccountingApiJsonSerializerService.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/infrastructure/impl/GoogleGsonAccountingApiJsonSerializerService.java new file mode 100644 index 000000000..c09348576 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/infrastructure/impl/GoogleGsonAccountingApiJsonSerializerService.java @@ -0,0 +1,75 @@ +package org.mifosplatform.accounting.api.infrastructure.impl; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.mifosng.platform.api.data.EntityIdentifier; +import org.mifosng.platform.api.infrastructure.PortfolioApiJsonSerializerService; +import org.mifosng.platform.infrastructure.api.GoogleGsonSerializerHelper; +import org.mifosplatform.accounting.api.data.GLAccountData; +import org.mifosplatform.accounting.api.data.GLClosureData; +import org.mifosplatform.accounting.api.infrastructure.AccountingApiJsonSerializerService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.google.gson.Gson; + +/** + * Implementation of {@link PortfolioApiJsonSerializerService} that uses + * google-gson to serialize Java object representation into JSON. + */ +@Service +public class GoogleGsonAccountingApiJsonSerializerService implements AccountingApiJsonSerializerService { + + private static final Set GL_ACCOUNT_DATA_PARAMETERS = new HashSet(Arrays.asList("id", "name", "parentId", "glCode", + "disabled", "manualEntriesAllowed", "classification", "headerAccount", "description")); + + private static final Set GL_ACCOUNT_CLOSURE_PARAMETERS = new HashSet(Arrays.asList("id", "officeId", "officeName", + "closingDate", "deleted", "createdDate", "lastUpdatedDate", "creatingByUserId", "lastUpdatedByUserId", "comments")); + + private final GoogleGsonSerializerHelper helper; + + @Autowired + public GoogleGsonAccountingApiJsonSerializerService(final GoogleGsonSerializerHelper helper) { + this.helper = helper; + } + + @Override + public String serializeEntityIdentifier(final EntityIdentifier identifier) { + final Set DATA_PARAMETERS = new HashSet(Arrays.asList("entityId")); + final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(DATA_PARAMETERS, false, + DATA_PARAMETERS); + return helper.serializedJsonFrom(gsonDeserializer, identifier); + } + + @Override + public String serializeGLAccountDataToJson(final boolean prettyPrint, final Set responseParameters, + final GLAccountData accountData) { + final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(GL_ACCOUNT_DATA_PARAMETERS, + prettyPrint, responseParameters); + return helper.serializedJsonFrom(gsonDeserializer, accountData); + } + + @Override + public String serializeGLAccountDataToJson(boolean prettyPrint, Set responseParameters, Collection accountDatas) { + final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(GL_ACCOUNT_DATA_PARAMETERS, + prettyPrint, responseParameters); + return helper.serializedJsonFrom(gsonDeserializer, accountDatas.toArray(new GLAccountData[accountDatas.size()])); + } + + @Override + public String serializeGLClosureDataToJson(boolean prettyPrint, Set responseParameters, GLClosureData closureData) { + final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(GL_ACCOUNT_CLOSURE_PARAMETERS, + prettyPrint, responseParameters); + return helper.serializedJsonFrom(gsonDeserializer, closureData); + } + + @Override + public String serializeGLClosureDataToJson(boolean prettyPrint, Set responseParameters, Collection closureDatas) { + final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(GL_ACCOUNT_DATA_PARAMETERS, + prettyPrint, responseParameters); + return helper.serializedJsonFrom(gsonDeserializer, closureDatas.toArray(new GLAccountData[closureDatas.size()])); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/domain/GLAccount.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/domain/GLAccount.java new file mode 100644 index 000000000..9f554956c --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/domain/GLAccount.java @@ -0,0 +1,116 @@ +package org.mifosplatform.accounting.domain; + +import java.util.LinkedList; +import java.util.List; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +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.BooleanUtils; +import org.apache.commons.lang.StringUtils; +import org.mifosplatform.accounting.api.commands.GLAccountCommand; +import org.springframework.data.jpa.domain.AbstractPersistable; + +@Entity +@Table(name = "acc_gl_account", uniqueConstraints = { @UniqueConstraint(columnNames = { "gl_code" }, name = "acc_gl_code") }) +public class GLAccount extends AbstractPersistable { + + @SuppressWarnings("unused") + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "parent_id") + private GLAccount parent; + + @OneToMany(fetch = FetchType.LAZY) + @JoinColumn(name = "parent_id") + private List children = new LinkedList(); + + @SuppressWarnings("unused") + @Column(name = "name", nullable = false, length = 45) + private String name; + + @SuppressWarnings("unused") + @Column(name = "gl_code", nullable = false, length = 100) + private String glCode; + + @SuppressWarnings("unused") + @Column(name = "disabled", nullable = false) + private boolean disabled = false; + + @SuppressWarnings("unused") + @Column(name = "manual_entries_allowed", nullable = false) + private boolean manualEntriesAllowed = true; + + @SuppressWarnings("unused") + @Column(name = "classification", nullable = false, length = 45) + private String classification; + + @Column(name = "header_account", nullable = false) + private boolean headerAccount; + + @SuppressWarnings("unused") + @Column(name = "description", nullable = true, length = 500) + private String description; + + public static GLAccount createNew(final GLAccount parent, final String name, final String glCode, final boolean disabled, + final boolean manualEntriesAllowed, final String classification, final boolean headerAccount, final String description) { + return new GLAccount(parent, name, glCode, disabled, manualEntriesAllowed, classification, headerAccount, description); + } + + protected GLAccount() { + // + } + + private GLAccount(final GLAccount parent, final String name, final String glCode, final boolean disabled, + final boolean manualEntriesAllowed, final String classification, final boolean headerAccount, final String description) { + this.parent = parent; + this.name = StringUtils.defaultIfEmpty(name, null); + this.glCode = StringUtils.defaultIfEmpty(glCode, null); + this.disabled = BooleanUtils.toBooleanDefaultIfNull(disabled, false); + this.manualEntriesAllowed = BooleanUtils.toBooleanDefaultIfNull(manualEntriesAllowed, true); + this.headerAccount = BooleanUtils.toBooleanDefaultIfNull(headerAccount, false); + this.classification = classification; + this.description = StringUtils.defaultIfEmpty(description, null); + } + + public void update(final GLAccountCommand command, final GLAccount parentGLAccount) { + if (command.isClassificationChanged()) { + this.classification = command.getClassification(); + } + if (command.isDescriptionChanged()) { + this.description = command.getDescription(); + } + if (command.isDisabledFlagChanged()) { + this.disabled = command.getDisabled(); + } + if (command.isGLCodeChanged()) { + this.glCode = command.getGlCode(); + } + if (command.isHeaderAccountFlagChanged()) { + this.headerAccount = command.getHeaderAccount(); + } + if (command.isManualEntriesAllowedFlagChanged()) { + this.manualEntriesAllowed = command.getManualEntriesAllowed(); + } + if (command.isNameChanged()) { + this.name = command.getName(); + } + if (command.isParentIdChanged()) { + this.parent = parentGLAccount; + } + } + + public boolean isHeaderAccount() { + return headerAccount; + } + + public List getChildren() { + return this.children; + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/domain/GLAccountRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/domain/GLAccountRepository.java new file mode 100644 index 000000000..7ba19a5e4 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/domain/GLAccountRepository.java @@ -0,0 +1,8 @@ +package org.mifosplatform.accounting.domain; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface GLAccountRepository extends JpaRepository, JpaSpecificationExecutor { + // no added behaviour +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/domain/GLClosure.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/domain/GLClosure.java new file mode 100755 index 000000000..0857e1cb9 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/domain/GLClosure.java @@ -0,0 +1,67 @@ +package org.mifosplatform.accounting.domain; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.UniqueConstraint; + +import org.apache.commons.lang.StringUtils; +import org.joda.time.LocalDate; +import org.mifosng.platform.infrastructure.AbstractAuditableCustom; +import org.mifosng.platform.organisation.domain.Office; +import org.mifosplatform.accounting.api.commands.GLClosureCommand; +import org.mifosplatform.infrastructure.user.domain.AppUser; + +@Entity +@Table(name = "acc_gl_closure", uniqueConstraints = { @UniqueConstraint(columnNames = { "office_id", "closing_date" }, name = "office_id_closing_date") }) +public class GLClosure extends AbstractAuditableCustom { + + @SuppressWarnings("unused") + @ManyToOne + @JoinColumn(name = "office_id", nullable = false) + private Office office; + + @SuppressWarnings("unused") + @Column(name = "is_deleted", nullable = false) + private boolean deleted = true; + + @SuppressWarnings("unused") + @Column(name = "closing_date") + @Temporal(TemporalType.DATE) + private Date closingDate; + + @SuppressWarnings("unused") + @Column(name = "comments", nullable = true, length = 500) + private String comments; + + public static GLClosure createNew(Office office, LocalDate closingDate, String comments) { + return new GLClosure(office, closingDate, comments); + } + + protected GLClosure() { + // + } + + public GLClosure(Office office, LocalDate closingDate, String comments) { + this.office = office; + this.deleted = false; + this.closingDate = closingDate.toDateMidnight().toDate(); + if (StringUtils.isNotBlank(comments)) { + this.comments = comments.trim(); + } else { + this.comments = null; + } + } + + public void update(final GLClosureCommand command) { + if (command.isCommentsChanged()) { + this.comments = command.getComments().trim(); + } + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/domain/GLClosureRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/domain/GLClosureRepository.java new file mode 100755 index 000000000..570a1f23f --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/domain/GLClosureRepository.java @@ -0,0 +1,8 @@ +package org.mifosplatform.accounting.domain; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface GLClosureRepository extends JpaRepository, JpaSpecificationExecutor { + // no added behaviour +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountDuplicateException.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountDuplicateException.java new file mode 100755 index 000000000..8e71c1771 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountDuplicateException.java @@ -0,0 +1,15 @@ +package org.mifosplatform.accounting.exceptions; + +import org.mifosng.platform.exceptions.AbstractPlatformDomainRuleException; + +/** + * A {@link RuntimeException} thrown when a GL Account with a given GL Code of + * the particular type is already present + */ +public class GLAccountDuplicateException extends AbstractPlatformDomainRuleException { + + public GLAccountDuplicateException(final String glCode) { + super("error.msg.glaccount.glcode.duplicate", "General Ledger Account with GL code " + glCode + " is already present", glCode); + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountInvalidClassificationException.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountInvalidClassificationException.java new file mode 100755 index 000000000..635120788 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountInvalidClassificationException.java @@ -0,0 +1,14 @@ +package org.mifosplatform.accounting.exceptions; + +import org.mifosng.platform.exceptions.AbstractPlatformDomainRuleException; + +/** + * A {@link RuntimeException} thrown when trying to fetch accounts belonging to + * an Invalid Type + */ +public class GLAccountInvalidClassificationException extends AbstractPlatformDomainRuleException { + + public GLAccountInvalidClassificationException(final String classification) { + super("error.msg.glaccount.classification.invalid", "The following COA classification is invalid: " + classification); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountInvalidDeleteException.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountInvalidDeleteException.java new file mode 100755 index 000000000..5df89f93b --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountInvalidDeleteException.java @@ -0,0 +1,26 @@ +package org.mifosplatform.accounting.exceptions; + +import org.mifosng.platform.exceptions.AbstractPlatformDomainRuleException; + +/** + * A {@link RuntimeException} thrown when a GL Account with a given GL Code of + * the particular type is already present + */ +public class GLAccountInvalidDeleteException extends AbstractPlatformDomainRuleException { + + /*** Enum of reasons for invalid delete **/ + public static enum GL_ACCOUNT_INVALID_DELETE_REASON { + TRANSANCTIONS_LOGGED, HAS_CHILDREN; + + public String errorMessage() { + if (name().toString().equalsIgnoreCase("TRANSANCTIONS_LOGGED")) { + return "This GL Account cannot be deleted as it has transactions logged against it"; + } else if (name().toString().equalsIgnoreCase("HAS_CHILDREN")) { return "Cannot delete this Header GL Account without first deleting or reassinging its children"; } + return name().toString(); + } + } + + public GLAccountInvalidDeleteException(final GL_ACCOUNT_INVALID_DELETE_REASON reason, final Long glAccountId) { + super("error.msg.glaccount.glcode.invalid.delete", reason.errorMessage(), glAccountId); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountInvalidParentException.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountInvalidParentException.java new file mode 100755 index 000000000..dd1c5aeca --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountInvalidParentException.java @@ -0,0 +1,15 @@ +package org.mifosplatform.accounting.exceptions; + +import org.mifosng.platform.exceptions.AbstractPlatformDomainRuleException; + +/** + * A {@link RuntimeException} thrown when trying to map invalid parents to a GL + * account + */ +public class GLAccountInvalidParentException extends AbstractPlatformDomainRuleException { + + public GLAccountInvalidParentException(long glAccountId) { + super("error.msg.glaccount.parent.invalid", "The account with id " + glAccountId + + " is a 'Detail' account and cannot be used as a parent", glAccountId); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountNotFoundException.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountNotFoundException.java new file mode 100755 index 000000000..36f0bd01f --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLAccountNotFoundException.java @@ -0,0 +1,13 @@ +package org.mifosplatform.accounting.exceptions; + +import org.mifosng.platform.exceptions.AbstractPlatformResourceNotFoundException; + +/** + * A {@link RuntimeException} thrown when GL account resources are not found. + */ +public class GLAccountNotFoundException extends AbstractPlatformResourceNotFoundException { + + public GLAccountNotFoundException(final Long id) { + super("error.msg.glaccount.id.invalid", "General Ledger account with identifier " + id + " does not exist", id); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLClosureDuplicateException.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLClosureDuplicateException.java new file mode 100755 index 000000000..beb2407ac --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLClosureDuplicateException.java @@ -0,0 +1,17 @@ +package org.mifosplatform.accounting.exceptions; + +import org.joda.time.LocalDate; +import org.mifosng.platform.exceptions.AbstractPlatformDomainRuleException; + +/** + * A {@link RuntimeException} thrown when a GL Closure for a given date and + * Office combination is already present + */ +public class GLClosureDuplicateException extends AbstractPlatformDomainRuleException { + + public GLClosureDuplicateException(final Long officeId, final LocalDate closureDate) { + super("error.msg.glclosure.glcode.duplicate", "An accounting closure for branch with Id " + officeId + + " already exists for the date " + closureDate, officeId, closureDate); + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLClosureNotFoundException.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLClosureNotFoundException.java new file mode 100755 index 000000000..71ec8cb15 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/exceptions/GLClosureNotFoundException.java @@ -0,0 +1,14 @@ +package org.mifosplatform.accounting.exceptions; + +import org.mifosng.platform.exceptions.AbstractPlatformResourceNotFoundException; + +/** + * A {@link RuntimeException} thrown when GL account closure resources are not + * found. + */ +public class GLClosureNotFoundException extends AbstractPlatformResourceNotFoundException { + + public GLClosureNotFoundException(final Long id) { + super("error.msg.glclosure.id.invalid", "Accounting Closure with identifier " + id + " does not exist", id); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLAccountCommandValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLAccountCommandValidator.java new file mode 100755 index 000000000..e3a19fb37 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLAccountCommandValidator.java @@ -0,0 +1,63 @@ +package org.mifosplatform.accounting.service; + +import java.util.ArrayList; +import java.util.List; + +import org.mifosng.platform.DataValidatorBuilder; +import org.mifosng.platform.api.data.ApiParameterError; +import org.mifosng.platform.exceptions.PlatformApiDataValidationException; +import org.mifosplatform.accounting.api.commands.GLAccountCommand; + +public class GLAccountCommandValidator { + + private final GLAccountCommand command; + + public GLAccountCommandValidator(GLAccountCommand command) { + this.command = command; + } + + public void validateForCreate() { + + List dataValidationErrors = new ArrayList(); + + DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("GLAccount"); + + baseDataValidator.reset().parameter("name").value(command.getName()).notBlank().notExceedingLengthOf(45); + + baseDataValidator.reset().parameter("glCode").value(command.getGlCode()).notBlank().notExceedingLengthOf(45); + + baseDataValidator.reset().parameter("parentId").value(command.getParentId()).ignoreIfNull().integerGreaterThanZero(); + + baseDataValidator.reset().parameter("classification").value(command.getClassification()).notBlank().notExceedingLengthOf(45); + + baseDataValidator.reset().parameter("description").value(command.getDescription()).ignoreIfNull().notExceedingLengthOf(500); + + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); } + } + + public void validateForUpdate() { + List dataValidationErrors = new ArrayList(); + + DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("GLAccount"); + + baseDataValidator.reset().parameter("name").value(command.getName()).ignoreIfNull().notBlank().notExceedingLengthOf(45); + + baseDataValidator.reset().parameter("glCode").ignoreIfNull().value(command.getGlCode()).notBlank().notExceedingLengthOf(45); + + baseDataValidator.reset().parameter("parentId").value(command.getParentId()).ignoreIfNull().integerGreaterThanZero(); + + baseDataValidator.reset().parameter("classification").value(command.getClassification()).ignoreIfNull().notBlank() + .notExceedingLengthOf(45); + + baseDataValidator.reset().parameter("description").value(command.getDescription()).ignoreIfNull().notBlank() + .notExceedingLengthOf(500); + + baseDataValidator.reset().anyOfNotNull(command.getName(), command.getGlCode(), command.getParentId(), command.getClassification(), + command.getDescription()); + + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); } + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLAccountReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLAccountReadPlatformService.java new file mode 100644 index 000000000..828b26c2a --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLAccountReadPlatformService.java @@ -0,0 +1,13 @@ +package org.mifosplatform.accounting.service; + +import java.util.List; + +import org.mifosplatform.accounting.api.data.GLAccountData; + +public interface GLAccountReadPlatformService { + + List retrieveAllGLAccounts(String accountClassification, String searchParam); + + GLAccountData retrieveGLAccountById(long glAccountId); + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLAccountWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLAccountWritePlatformService.java new file mode 100644 index 000000000..0799e18e3 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLAccountWritePlatformService.java @@ -0,0 +1,17 @@ +package org.mifosplatform.accounting.service; + +import org.mifosplatform.accounting.api.commands.GLAccountCommand; +import org.springframework.security.access.prepost.PreAuthorize; + +public interface GLAccountWritePlatformService { + + @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'ORGANISATION_ADMINISTRATION_SUPER_USER', 'CREATE_GL_ACCOUNT')") + Long createGLAccount(GLAccountCommand command); + + @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'ORGANISATION_ADMINISTRATION_SUPER_USER', 'UPDATE_GL_ACCOUNT')") + Long updateGLAccount(Long glAccountId, GLAccountCommand command); + + @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'ORGANISATION_ADMINISTRATION_SUPER_USER', 'DELETE_GL_ACCOUNT')") + Long deleteGLAccount(Long glAccountId); + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLClosureCommandValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLClosureCommandValidator.java new file mode 100755 index 000000000..ee9df9071 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLClosureCommandValidator.java @@ -0,0 +1,48 @@ +package org.mifosplatform.accounting.service; + +import java.util.ArrayList; +import java.util.List; + +import org.mifosng.platform.DataValidatorBuilder; +import org.mifosng.platform.api.data.ApiParameterError; +import org.mifosng.platform.exceptions.PlatformApiDataValidationException; +import org.mifosplatform.accounting.api.commands.GLClosureCommand; + +public class GLClosureCommandValidator { + + private final GLClosureCommand command; + + public GLClosureCommandValidator(GLClosureCommand command) { + this.command = command; + } + + public void validateForCreate() { + + List dataValidationErrors = new ArrayList(); + + DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("GLClosure"); + + baseDataValidator.reset().parameter("closingDate").value(command.getClosingDate()).notBlank(); + + baseDataValidator.reset().parameter("officeId").value(command.getOfficeId()).notNull().integerGreaterThanZero(); + + baseDataValidator.reset().parameter("comments").value(command.getComments()).ignoreIfNull().notExceedingLengthOf(500); + + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); } + } + + public void validateForUpdate() { + List dataValidationErrors = new ArrayList(); + + DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("GLClosure"); + + baseDataValidator.reset().parameter("comments").value(command.getComments()).ignoreIfNull().notExceedingLengthOf(500); + + baseDataValidator.reset().anyOfNotNull(command.getComments()); + + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); } + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLClosureReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLClosureReadPlatformService.java new file mode 100755 index 000000000..5fcad885e --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLClosureReadPlatformService.java @@ -0,0 +1,13 @@ +package org.mifosplatform.accounting.service; + +import java.util.List; + +import org.mifosplatform.accounting.api.data.GLClosureData; + +public interface GLClosureReadPlatformService { + + List retrieveAllGLClosures(Long OfficeId); + + GLClosureData retrieveGLClosureById(long glClosureId); + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLClosureWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLClosureWritePlatformService.java new file mode 100755 index 000000000..a3ddef648 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLClosureWritePlatformService.java @@ -0,0 +1,17 @@ +package org.mifosplatform.accounting.service; + +import org.mifosplatform.accounting.api.commands.GLClosureCommand; +import org.springframework.security.access.prepost.PreAuthorize; + +public interface GLClosureWritePlatformService { + + @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'ORGANISATION_ADMINISTRATION_SUPER_USER', 'CREATE_GL_CLOSURE')") + Long createGLClosure(GLClosureCommand command); + + @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'ORGANISATION_ADMINISTRATION_SUPER_USER', 'UPDATE_GL_CLOSURE')") + Long updateGLClosure(Long glClosureId, GLClosureCommand command); + + @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'ORGANISATION_ADMINISTRATION_SUPER_USER', 'DELETE_GL_CLOSURE')") + Long deleteGLClosure(Long glClosureId); + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLAccountReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLAccountReadPlatformServiceImpl.java new file mode 100644 index 000000000..527f108a1 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLAccountReadPlatformServiceImpl.java @@ -0,0 +1,101 @@ +package org.mifosplatform.accounting.service.impl; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.mifosng.platform.infrastructure.TenantAwareRoutingDataSource; +import org.mifosng.platform.security.PlatformSecurityContext; +import org.mifosplatform.accounting.AccountingConstants.GL_ACCOUNT_CLASSIFICATION; +import org.mifosplatform.accounting.api.data.GLAccountData; +import org.mifosplatform.accounting.exceptions.GLAccountInvalidClassificationException; +import org.mifosplatform.accounting.exceptions.GLAccountNotFoundException; +import org.mifosplatform.accounting.service.GLAccountReadPlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Service; + +@Service +public class GLAccountReadPlatformServiceImpl implements GLAccountReadPlatformService { + + private final JdbcTemplate jdbcTemplate; + @SuppressWarnings("unused") + private final PlatformSecurityContext context; + + @Autowired + public GLAccountReadPlatformServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource) { + this.context = context; + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + private static final class GLAccountMapper implements RowMapper { + + public String schema() { + return " id as id, name as name, parent_id as parentId, gl_code as glCode, disabled as disabled, manual_entries_allowed as manualEntriesAllowed, " + + "classification as classification, header_account as headerAccount, description as description " + + "from acc_gl_account"; + } + + @Override + public GLAccountData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + + Long id = rs.getLong("id"); + String name = rs.getString("name"); + Long parentId = rs.getLong("parentId"); + String glCode = rs.getString("glCode"); + boolean disabled = rs.getBoolean("disabled"); + boolean manualEntriesAllowed = rs.getBoolean("manualEntriesAllowed"); + String classification = rs.getString("classification"); + boolean headerAccount = rs.getBoolean("headerAccount"); + String description = rs.getString("description"); + + return new GLAccountData(id, name, parentId, glCode, disabled, manualEntriesAllowed, classification, headerAccount, description); + } + } + + @Override + public List retrieveAllGLAccounts(String accountClassification, String searchParam) { + if (StringUtils.isNotBlank(accountClassification)) { + if (!checkValidGLAccountClassification(accountClassification)) { throw new GLAccountInvalidClassificationException( + accountClassification); } + } + + GLAccountMapper rm = new GLAccountMapper(); + String sql = "select " + rm.schema(); + if (StringUtils.isNotBlank(accountClassification) && searchParam != null) { + sql += " where classification like ? and ( name like %?% or glCode like %?% )"; + } else if (StringUtils.isNotBlank(accountClassification)) { + sql += " where classification like ?"; + } else if (searchParam != null) { + sql += " where ( name like %?% or glCode like %?% )"; + } + sql = sql + " order by glCode"; + return this.jdbcTemplate.query(sql, rm, new Object[] { accountClassification, searchParam }); + } + + @Override + public GLAccountData retrieveGLAccountById(long glAccountId) { + try { + + GLAccountMapper rm = new GLAccountMapper(); + String sql = "select " + rm.schema() + " where id = ?"; + + GLAccountData glAccountData = this.jdbcTemplate.queryForObject(sql, rm, new Object[] { glAccountId }); + + return glAccountData; + } catch (EmptyResultDataAccessException e) { + throw new GLAccountNotFoundException(glAccountId); + } + } + + private static boolean checkValidGLAccountClassification(final String entityType) { + for (GL_ACCOUNT_CLASSIFICATION classification : GL_ACCOUNT_CLASSIFICATION.values()) { + if (classification.name().equalsIgnoreCase(entityType)) { return true; } + } + return false; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLAccountWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLAccountWritePlatformServiceJpaRepositoryImpl.java new file mode 100644 index 000000000..070a2e58b --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLAccountWritePlatformServiceJpaRepositoryImpl.java @@ -0,0 +1,126 @@ +package org.mifosplatform.accounting.service.impl; + +import org.mifosng.platform.exceptions.PlatformDataIntegrityException; +import org.mifosplatform.accounting.api.commands.GLAccountCommand; +import org.mifosplatform.accounting.domain.GLAccount; +import org.mifosplatform.accounting.domain.GLAccountRepository; +import org.mifosplatform.accounting.exceptions.GLAccountDuplicateException; +import org.mifosplatform.accounting.exceptions.GLAccountInvalidDeleteException; +import org.mifosplatform.accounting.exceptions.GLAccountInvalidParentException; +import org.mifosplatform.accounting.exceptions.GLAccountNotFoundException; +import org.mifosplatform.accounting.exceptions.GLAccountInvalidDeleteException.GL_ACCOUNT_INVALID_DELETE_REASON; +import org.mifosplatform.accounting.service.GLAccountCommandValidator; +import org.mifosplatform.accounting.service.GLAccountWritePlatformService; +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 GLAccountWritePlatformServiceJpaRepositoryImpl implements GLAccountWritePlatformService { + + private final static Logger logger = LoggerFactory.getLogger(GLAccountWritePlatformServiceJpaRepositoryImpl.class); + + private final GLAccountRepository glAccountRepository; + + @Autowired + public GLAccountWritePlatformServiceJpaRepositoryImpl(final GLAccountRepository glAccountRepository) { + this.glAccountRepository = glAccountRepository; + } + + @Transactional + @Override + public Long createGLAccount(GLAccountCommand command) { + try { + GLAccountCommandValidator validator = new GLAccountCommandValidator(command); + validator.validateForCreate(); + + // check parent is valid + GLAccount parentGLAccount = null; + if (command.getParentId() != null) { + parentGLAccount = validateParentGLAccount(command); + } + GLAccount glAccount = GLAccount.createNew(parentGLAccount, command.getName(), command.getGlCode(), command.getDisabled(), + command.getManualEntriesAllowed(), command.getClassification(), command.getHeaderAccount(), command.getDescription()); + + this.glAccountRepository.saveAndFlush(glAccount); + + return glAccount.getId(); + } catch (DataIntegrityViolationException dve) { + handleGLAccountDataIntegrityIssues(command, dve); + return Long.valueOf(-1); + } + } + + @Transactional + @Override + public Long updateGLAccount(Long glAccountId, GLAccountCommand command) { + GLAccountCommandValidator validator = new GLAccountCommandValidator(command); + validator.validateForUpdate(); + + // is the glAccount valid + GLAccount glAccount = glAccountRepository.findOne(glAccountId); + if (glAccount == null) { throw new GLAccountNotFoundException(glAccountId); } + + // is the new parent valid + GLAccount parentGLAccount = null; + if (command.isParentIdChanged()) { + parentGLAccount = validateParentGLAccount(command); + } + + glAccount.update(command, parentGLAccount); + + this.glAccountRepository.saveAndFlush(glAccount); + + return glAccount.getId(); + } + + /** + * @param command + * @return + */ + private GLAccount validateParentGLAccount(GLAccountCommand command) { + GLAccount parentGLAccount; + parentGLAccount = glAccountRepository.findOne(command.getParentId()); + if (parentGLAccount == null) { throw new GLAccountNotFoundException(command.getParentId()); } + // ensure parent is not a detail account + if (parentGLAccount.isHeaderAccount()) { throw new GLAccountInvalidParentException(command.getParentId()); } + return parentGLAccount; + } + + /** + * @param command + * @param dve + */ + private void handleGLAccountDataIntegrityIssues(final GLAccountCommand command, DataIntegrityViolationException dve) { + Throwable realCause = dve.getMostSpecificCause(); + if (realCause.getMessage().contains("acc_gl_code")) { + String glCode = command.getGlCode(); + throw new GLAccountDuplicateException(glCode); + } + + logger.error(dve.getMessage(), dve); + throw new PlatformDataIntegrityException("error.msg.glAccount.unknown.data.integrity.issue", + "Unknown data integrity issue with resource GL Account: " + realCause.getMessage()); + } + + @Transactional + @Override + public Long deleteGLAccount(Long glAccountId) { + final GLAccount glAccount = this.glAccountRepository.findOne(glAccountId); + + if (glAccount == null) { throw new GLAccountNotFoundException(glAccountId); } + + // validate this isn't a header account that has children + if (glAccount.isHeaderAccount() && glAccount.getChildren().size() > 0) { throw new GLAccountInvalidDeleteException( + GL_ACCOUNT_INVALID_DELETE_REASON.HAS_CHILDREN, glAccountId); } + + // TODO: does this account have transactions logged against it + + this.glAccountRepository.delete(glAccount); + + return glAccountId; + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLClosureReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLClosureReadPlatformServiceImpl.java new file mode 100755 index 000000000..9b385a6b2 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLClosureReadPlatformServiceImpl.java @@ -0,0 +1,92 @@ +package org.mifosplatform.accounting.service.impl; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +import org.joda.time.LocalDate; +import org.mifosng.platform.infrastructure.JdbcSupport; +import org.mifosng.platform.infrastructure.TenantAwareRoutingDataSource; +import org.mifosng.platform.security.PlatformSecurityContext; +import org.mifosplatform.accounting.api.data.GLClosureData; +import org.mifosplatform.accounting.exceptions.GLClosureNotFoundException; +import org.mifosplatform.accounting.service.GLClosureReadPlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Service; + +@Service +public class GLClosureReadPlatformServiceImpl implements GLClosureReadPlatformService { + + private final JdbcTemplate jdbcTemplate; + @SuppressWarnings("unused") + private final PlatformSecurityContext context; + + @Autowired + public GLClosureReadPlatformServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource) { + this.context = context; + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + private static final class GLClosureMapper implements RowMapper { + + public String schema() { + return " glClosure.id as id, glClosure.office_id as officeId,office.name as officeName ,glClosure.closing_date as closingDate," + + " glClosure.is_deleted as isDeleted, creatingUser.id as creatingUserId,creatingUser.username as creatingUserName," + + " updatingUser.id as updatingUserId,updatingUser.username as updatingUserName, glClosure.created_date as createdDate," + + " glClosure.lastmodified_date as updatedDate from acc_gl_Closure as glClosure, m_appuser as creatingUser, " + + " glClosure.comments as comments " + + " m_appuser as updatingUser,m_office as office where glClosure.createdby_id=creatingUser.id and " + + " glClosure.lastmodifiedby_id=updatingUser.id and glClosure.office_id=office.id"; + } + + @Override + public GLClosureData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + + Long id = rs.getLong("id"); + Long officeId = rs.getLong("officeId"); + String officeName = rs.getString("officeName"); + LocalDate closingDate = JdbcSupport.getLocalDate(rs, "closingDate"); + Boolean deleted = rs.getBoolean("isDeleted"); + LocalDate createdDate = JdbcSupport.getLocalDate(rs, "createdDate"); + LocalDate lastUpdatedDate = JdbcSupport.getLocalDate(rs, "updatedDate"); + Long creatingByUserId = rs.getLong("creatingUserId"); + Long lastUpdatedByUserId = rs.getLong("updatingUserId"); + String comments = rs.getString("comments"); + + return new GLClosureData(id, officeId, officeName, closingDate, deleted, createdDate, lastUpdatedDate, creatingByUserId, + lastUpdatedByUserId, comments); + } + } + + @Override + public List retrieveAllGLClosures(Long officeId) { + GLClosureMapper rm = new GLClosureMapper(); + + String sql = "select " + rm.schema() + " and glClosure.is_deleted = 0"; + if (officeId != null && officeId != 0) { + sql += " and glClosure.office_id = ?"; + } + + sql = sql + " glClosure.closing_date"; + return this.jdbcTemplate.query(sql, rm, new Object[] { officeId }); + } + + @Override + public GLClosureData retrieveGLClosureById(long glClosureId) { + try { + + GLClosureMapper rm = new GLClosureMapper(); + String sql = "select " + rm.schema() + " and glClosure,id = ?"; + + GLClosureData glAccountData = this.jdbcTemplate.queryForObject(sql, rm, new Object[] { glClosureId }); + + return glAccountData; + } catch (EmptyResultDataAccessException e) { + throw new GLClosureNotFoundException(glClosureId); + } + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLClosureWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLClosureWritePlatformServiceJpaRepositoryImpl.java new file mode 100755 index 000000000..6f527d329 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLClosureWritePlatformServiceJpaRepositoryImpl.java @@ -0,0 +1,103 @@ +package org.mifosplatform.accounting.service.impl; + +import org.mifosng.platform.exceptions.OfficeNotFoundException; +import org.mifosng.platform.exceptions.PlatformDataIntegrityException; +import org.mifosng.platform.organisation.domain.Office; +import org.mifosng.platform.organisation.domain.OfficeRepository; +import org.mifosplatform.accounting.api.commands.GLClosureCommand; +import org.mifosplatform.accounting.domain.GLClosure; +import org.mifosplatform.accounting.domain.GLClosureRepository; +import org.mifosplatform.accounting.exceptions.GLClosureDuplicateException; +import org.mifosplatform.accounting.exceptions.GLClosureNotFoundException; +import org.mifosplatform.accounting.service.GLClosureCommandValidator; +import org.mifosplatform.accounting.service.GLClosureWritePlatformService; +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 GLClosureWritePlatformServiceJpaRepositoryImpl implements GLClosureWritePlatformService { + + private final static Logger logger = LoggerFactory.getLogger(GLClosureWritePlatformServiceJpaRepositoryImpl.class); + + private final GLClosureRepository glClosureRepository; + private final OfficeRepository officeRepository; + + @Autowired + public GLClosureWritePlatformServiceJpaRepositoryImpl(final GLClosureRepository glClosureRepository, + final OfficeRepository officeRepository) { + this.glClosureRepository = glClosureRepository; + this.officeRepository = officeRepository; + } + + @Transactional + @Override + public Long createGLClosure(GLClosureCommand command) { + try { + GLClosureCommandValidator validator = new GLClosureCommandValidator(command); + validator.validateForCreate(); + + // check office is valid + final Office office = this.officeRepository.findOne(command.getOfficeId()); + if (office == null) { throw new OfficeNotFoundException(command.getOfficeId()); } + + GLClosure glClosure = GLClosure.createNew(office, command.getClosingDate(), command.getComments()); + + this.glClosureRepository.saveAndFlush(glClosure); + + return glClosure.getId(); + } catch (DataIntegrityViolationException dve) { + handleGLClosureIntegrityIssues(command, dve); + return Long.valueOf(-1); + } + } + + @Transactional + @Override + public Long updateGLClosure(Long glClosureId, GLClosureCommand command) { + GLClosureCommandValidator validator = new GLClosureCommandValidator(command); + validator.validateForUpdate(); + + // is the glClosure valid + GLClosure glClosure = glClosureRepository.findOne(glClosureId); + if (glClosure == null) { throw new GLClosureNotFoundException(glClosureId); } + + glClosure.update(command); + + this.glClosureRepository.saveAndFlush(glClosure); + + return glClosure.getId(); + } + + @Transactional + @Override + public Long deleteGLClosure(Long glClosureId) { + final GLClosure glClosure = this.glClosureRepository.findOne(glClosureId); + + if (glClosure == null) { throw new GLClosureNotFoundException(glClosureId); } + + // TODO: check if any closures are present for this branch at a later + // date than this closure + + this.glClosureRepository.delete(glClosure); + + return glClosureId; + } + + /** + * @param command + * @param dve + */ + private void handleGLClosureIntegrityIssues(final GLClosureCommand command, DataIntegrityViolationException dve) { + Throwable realCause = dve.getMostSpecificCause(); + if (realCause.getMessage().contains("office_id_closing_date")) { throw new GLClosureDuplicateException(command.getOfficeId(), + command.getClosingDate()); } + + logger.error(dve.getMessage(), dve); + throw new PlatformDataIntegrityException("error.msg.glClosure.unknown.data.integrity.issue", + "Unknown data integrity issue with resource GL Closure: " + realCause.getMessage()); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/user/command/RolePermissionCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/user/command/RolePermissionCommand.java index 4031bdf61..2f3826d12 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/user/command/RolePermissionCommand.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/user/command/RolePermissionCommand.java @@ -11,7 +11,7 @@ public class RolePermissionCommand { private final Map permissions; private final transient boolean makerCheckerApproval; - + public RolePermissionCommand(final Long roleId, final Map permissionsMap, final boolean makerCheckerApproval) { this.roleId = roleId; this.permissions = permissionsMap; @@ -25,7 +25,7 @@ public class RolePermissionCommand { public Long getRoleId() { return this.roleId; } - + public boolean isApprovedByChecker() { return this.makerCheckerApproval; }