From dde6eaec2acc8031f7e1ee0fba65907bbaeee7b4 Mon Sep 17 00:00:00 2001 From: Satish Date: Thu, 8 Dec 2016 09:48:28 +0530 Subject: [PATCH] Entity datatable check implementation --- .../service/CommandWrapperBuilder.java | 18 + .../core/data/DataValidatorBuilder.java | 20 ++ .../api/EntityDatatableChecksApiResource.java | 125 +++++++ .../data/DatatableCheckStatusData.java | 31 ++ .../dataqueries/data/DatatableChecksData.java | 33 ++ .../dataqueries/data/DatatableData.java | 15 + .../data/EntityDataTableChecksData.java | 51 +++ .../EntityDataTableChecksTemplateData.java | 56 ++++ .../dataqueries/data/EntityTables.java | 108 ++++++ .../dataqueries/data/StatusEnum.java | 103 ++++++ .../domain/EntityDatatableChecks.java | 102 ++++++ .../EntityDatatableChecksRepository.java | 54 +++ .../DatatabaleEntryRequiredException.java | 45 +++ ...yDatatableCheckAlreadyExistsException.java | 43 +++ ...EntityDatatableCheckNotAllowException.java | 35 ++ ...tyDatatableCheckNotSupportedException.java | 39 +++ ...ntityDatatableChecksNotFoundException.java | 32 ++ ...teEntityDatatableChecksCommandHandler.java | 48 +++ ...teEntityDatatableChecksCommandHandler.java | 48 +++ .../EntityDatatableChecksDataValidator.java | 98 ++++++ ...atatableChecksReadPlatformServiceImpl.java | 217 ++++++++++++ .../EntityDatatableChecksReadService.java | 37 ++ ...tyDatatableChecksWritePlatformService.java | 34 ++ ...tatableChecksWritePlatformServiceImpl.java | 315 ++++++++++++++++++ .../service/ReadWriteNonCoreDataService.java | 3 + .../ReadWriteNonCoreDataServiceImpl.java | 64 ++-- .../client/api/ClientApiConstants.java | 6 +- .../portfolio/client/data/ClientData.java | 29 +- .../client/data/ClientDataValidator.java | 25 +- .../ClientReadPlatformServiceImpl.java | 16 +- ...WritePlatformServiceJpaRepositoryImpl.java | 45 +-- .../group/api/CentersApiResource.java | 18 +- .../group/api/GroupingTypesApiConstants.java | 12 +- .../group/api/GroupsApiResource.java | 14 +- .../portfolio/group/data/CenterData.java | 8 + .../group/data/GroupGeneralData.java | 8 + .../GroupingTypesDataValidator.java | 16 + ...WritePlatformServiceJpaRepositoryImpl.java | 55 +-- .../loanaccount/api/LoanApiConstants.java | 1 + .../loanaccount/api/LoansApiResource.java | 23 +- .../loanaccount/data/LoanAccountData.java | 12 +- ...anApplicationCommandFromApiJsonHelper.java | 8 +- ...WritePlatformServiceJpaRepositoryImpl.java | 69 ++-- ...WritePlatformServiceJpaRepositoryImpl.java | 94 ++---- .../savings/SavingsApiConstants.java | 6 +- .../savings/data/SavingsAccountData.java | 8 + .../data/SavingsAccountDataValidator.java | 5 + ...SavingsAccountReadPlatformServiceImpl.java | 14 +- ...WritePlatformServiceJpaRepositoryImpl.java | 61 ++-- ...WritePlatformServiceJpaRepositoryImpl.java | 49 ++- .../core_db/V324__datatable_checks.sql | 46 +++ 51 files changed, 2133 insertions(+), 289 deletions(-) create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/EntityDatatableChecksApiResource.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableCheckStatusData.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableChecksData.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityDataTableChecksData.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityDataTableChecksTemplateData.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityTables.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/StatusEnum.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/EntityDatatableChecks.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/EntityDatatableChecksRepository.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/DatatabaleEntryRequiredException.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckAlreadyExistsException.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckNotAllowException.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckNotSupportedException.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableChecksNotFoundException.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/handler/CreateEntityDatatableChecksCommandHandler.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/handler/DeleteEntityDatatableChecksCommandHandler.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksDataValidator.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadPlatformServiceImpl.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadService.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksWritePlatformService.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksWritePlatformServiceImpl.java create mode 100644 fineract-provider/src/main/resources/sql/migrations/core_db/V324__datatable_checks.sql diff --git a/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java b/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java index 0cdc7e2f0..2ad6b2201 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java +++ b/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java @@ -2756,6 +2756,24 @@ public class CommandWrapperBuilder { return this; } + public CommandWrapperBuilder createEntityDatatableChecks(final String json) { + this.actionName = "CREATE"; + this.entityName = "ENTITY_DATATABLE_CHECK"; + this.entityId = null; + this.href = "/entityDatatableChecks/"; + this.json = json; + return this; + } + + public CommandWrapperBuilder deleteEntityDatatableChecks(final long entityDatatableCheckId, final String json) { + this.actionName = "DELETE"; + this.entityName = "ENTITY_DATATABLE_CHECK"; + this.entityId = entityDatatableCheckId; + this.href = "/entityDatatableChecks/" + entityDatatableCheckId; + this.json = json; + return this; + } + public CommandWrapperBuilder addSelfServiceBeneficiaryTPT() { this.actionName = "CREATE"; this.entityName = "SSBENEFICIARYTPT"; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/data/DataValidatorBuilder.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/data/DataValidatorBuilder.java index e62861970..def8d8815 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/data/DataValidatorBuilder.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/data/DataValidatorBuilder.java @@ -278,6 +278,26 @@ public class DataValidatorBuilder { return this; } + public DataValidatorBuilder isOneOfTheseStringValues(final List valuesList) { + if (this.value == null && this.ignoreNullValue) { return this; } + + final String valuesListStr = StringUtils.join(valuesList, ", "); + + if (this.value == null || !valuesList.contains(this.value.toString().toLowerCase())) { + final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".") + .append(this.parameter).append(".is.not.one.of.expected.enumerations"); + final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter) + .append(" must be one of [ ").append(valuesListStr).append(" ] ").append("."); + + final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), + defaultEnglishMessage.toString(), this.parameter, this.value, valuesList); + + this.dataValidationErrors.add(error); + } + + return this; + } + public DataValidatorBuilder isNotOneOfTheseValues(final Object... values) { if (this.value == null && this.ignoreNullValue) { return this; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/EntityDatatableChecksApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/EntityDatatableChecksApiResource.java new file mode 100644 index 000000000..880687495 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/EntityDatatableChecksApiResource.java @@ -0,0 +1,125 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.api; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.UriInfo; + +import org.apache.fineract.commands.domain.CommandWrapper; +import org.apache.fineract.commands.service.CommandWrapperBuilder; +import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; +import org.apache.fineract.infrastructure.core.api.ApiParameterHelper; +import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer; +import org.apache.fineract.infrastructure.core.service.Page; +import org.apache.fineract.infrastructure.core.service.SearchParameters; +import org.apache.fineract.infrastructure.dataqueries.data.EntityDataTableChecksData; +import org.apache.fineract.infrastructure.dataqueries.data.EntityDataTableChecksTemplateData; +import org.apache.fineract.infrastructure.dataqueries.data.GenericResultsetData; +import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService; +import org.apache.fineract.infrastructure.dataqueries.service.GenericDataService; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +@Path("/entityDatatableChecks") +@Component +@Scope("singleton") +public class EntityDatatableChecksApiResource { + + private final PlatformSecurityContext context; + private final GenericDataService genericDataService; + private final EntityDatatableChecksReadService readEntityDatatableChecksService; + private final ToApiJsonSerializer toApiJsonSerializer; + private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; + private final static org.slf4j.Logger logger = LoggerFactory.getLogger(EntityDatatableChecksApiResource.class); + + @Autowired + public EntityDatatableChecksApiResource(final PlatformSecurityContext context, final GenericDataService genericDataService, + final EntityDatatableChecksReadService readEntityDatatableChecksService, + final ToApiJsonSerializer toApiJsonSerializer, + final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { + this.context = context; + this.genericDataService = genericDataService; + this.readEntityDatatableChecksService = readEntityDatatableChecksService; + this.toApiJsonSerializer = toApiJsonSerializer; + this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; + } + + @GET + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveAll(@Context final UriInfo uriInfo, @QueryParam("status") final Long status, + @QueryParam("entity") final String entity, @QueryParam("productId") final Long productId, + @QueryParam("offset") final Integer offset, @QueryParam("limit") final Integer limit) { + final SearchParameters searchParameters = SearchParameters.forPagination(offset, limit); + final Page result = this.readEntityDatatableChecksService.retrieveAll(searchParameters, status, entity, + productId); + + final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); + return this.toApiJsonSerializer.serializePretty(prettyPrint, result); + } + + @GET + @Path("template") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String getTemplate(@Context final UriInfo uriInfo) { + + final EntityDataTableChecksTemplateData result = this.readEntityDatatableChecksService.retrieveTemplate(); + + final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); + return this.toApiJsonSerializer.serializePretty(prettyPrint, result); + } + + @POST + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String createEntityDatatableCheck(final String apiRequestBodyAsJson) { + + final CommandWrapper commandRequest = new CommandWrapperBuilder().createEntityDatatableChecks(apiRequestBodyAsJson).build(); + final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + return this.toApiJsonSerializer.serialize(result); + } + + @DELETE + @Path("{entityDatatableCheckId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String deleteDatatable(@PathParam("entityDatatableCheckId") final long entityDatatableCheckId, final String apiRequestBodyAsJson) { + + final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteEntityDatatableChecks(entityDatatableCheckId, + apiRequestBodyAsJson).build(); + + final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + return this.toApiJsonSerializer.serialize(result); + } + +} \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableCheckStatusData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableCheckStatusData.java new file mode 100644 index 000000000..43f0047aa --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableCheckStatusData.java @@ -0,0 +1,31 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.data; + +public class DatatableCheckStatusData { + + private final String name; + private final int code; + + public DatatableCheckStatusData(final String name, final int code) { + this.name = name; + this.code = code; + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableChecksData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableChecksData.java new file mode 100644 index 000000000..361e847f2 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableChecksData.java @@ -0,0 +1,33 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.data; + +import java.io.Serializable; + +public class DatatableChecksData implements Serializable { + + private static final long serialVersionUID = 3113568562509206452L; + private final String entity; + private final String dataTableName; + + public DatatableChecksData(final String entity, final String dataTableName) { + this.entity = entity; + this.dataTableName = dataTableName; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableData.java index f23b8ff0a..42491d033 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableData.java @@ -45,4 +45,19 @@ public class DatatableData { this.columnHeaderData = columnHeaderData; } + + public boolean hasColumn(final String columnName){ + + for(ResultsetColumnHeaderData c : this.columnHeaderData){ + + if(c.getColumnName().equals(columnName)) return true; + } + + return false; + } + + public String getRegisteredTableName(){ + return registeredTableName; + } + } \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityDataTableChecksData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityDataTableChecksData.java new file mode 100644 index 000000000..0a6482f36 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityDataTableChecksData.java @@ -0,0 +1,51 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.data; + +import java.io.Serializable; + +import org.apache.fineract.infrastructure.core.data.EnumOptionData; + +/** + * Immutable data object for role data. + */ +public class EntityDataTableChecksData implements Serializable { + + private final long id; + private final String entity; + private final EnumOptionData status; + private final String datatableName; + private final boolean systemDefined; + private final Long order; + private final Long productId; + private final String productName; + + public EntityDataTableChecksData(final long id, final String entity, final EnumOptionData status, final String datatableName, + final boolean systemDefined, final Long loanProductId, final String productName) { + this.id = id; + this.entity = entity; + this.status = status; + this.datatableName = datatableName; + this.systemDefined = systemDefined; + this.order = id; + this.productId = loanProductId; + this.productName = productName; + } + +} \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityDataTableChecksTemplateData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityDataTableChecksTemplateData.java new file mode 100644 index 000000000..962c08deb --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityDataTableChecksTemplateData.java @@ -0,0 +1,56 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.data; + +import java.io.Serializable; +import java.util.Collection; +import java.util.List; + +import org.apache.fineract.portfolio.loanproduct.data.LoanProductData; +import org.apache.fineract.portfolio.savings.data.SavingsProductData; + +/** + * Immutable data object for role data. + */ +public class EntityDataTableChecksTemplateData implements Serializable { + + private final List entities; + private final List statusClient; + private final List statusGroup; + private final List statusSavings; + private final List statusLoans; + private final List datatables; + private final Collection loanProductDatas; + private final Collection savingsProductDatas; + + public EntityDataTableChecksTemplateData(final List entities, List statusClient, + List statusGroup, List statusSavings, + List statusLoans, List datatables, + Collection loanProductDatas, Collection savingsProductDatas) { + + this.entities = entities; + this.statusClient = statusClient; + this.statusGroup = statusGroup; + this.statusSavings = statusSavings; + this.statusLoans = statusLoans; + this.datatables = datatables; + this.loanProductDatas = loanProductDatas; + this.savingsProductDatas = savingsProductDatas; + } +} \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityTables.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityTables.java new file mode 100644 index 000000000..51f77c3e0 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityTables.java @@ -0,0 +1,108 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.data; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public enum EntityTables { + + CLIENT("m_client", + new Integer[]{StatusEnum.CREATE.getCode(), + StatusEnum.ACTIVATE.getCode(), + StatusEnum.CLOSE.getCode()}, + "client_id"), + LOAN("m_loan", + new Integer[]{StatusEnum.CREATE.getCode(), + StatusEnum.APPROVE.getCode(), + StatusEnum.ACTIVATE.getCode(), + StatusEnum.WITHDRAWN.getCode(), + StatusEnum.REJECTED.getCode(), + StatusEnum.WRITE_OFF.getCode()}, + "loan_id"), + GROUP("m_group", + new Integer[]{StatusEnum.CREATE.getCode(), + StatusEnum.ACTIVATE.getCode(), + StatusEnum.CLOSE.getCode(),}, + "group_id"), + SAVING("m_savings_account", + new Integer[]{StatusEnum.CREATE.getCode(), + StatusEnum.APPROVE.getCode(), + StatusEnum.ACTIVATE.getCode(), + StatusEnum.WITHDRAWN.getCode(), + StatusEnum.REJECTED.getCode(), + StatusEnum.CLOSE.getCode()}, + "savings_account_id"); + + private static final Map lookup = new HashMap(); + static { + for (EntityTables d : EntityTables.values()) + lookup.put(d.getName(), d); + } + + private String name; + + private Integer[] codes; + + private String foreignKeyColumnNameOnDatatable; + + private EntityTables(String name, Integer[] codes, String foreignKeyColumnNameOnDatatable) { + this.name = name; + this.codes = codes; + this.foreignKeyColumnNameOnDatatable = foreignKeyColumnNameOnDatatable; + } + + public static List getEntitiesList() { + + List data = new ArrayList(); + + for (EntityTables entity : EntityTables.values()) { + data.add(entity.name); + } + + return data; + + } + + public static Integer[] getStatus(String name) { + if (lookup.get(name) != null) { + return lookup.get(name).getCodes(); + } + return new Integer[]{}; + } + + public Integer[] getCodes() { + return this.codes; + } + + public String getName() { + return name; + } + + public String getForeignKeyColumnNameOnDatatable() { + return this.foreignKeyColumnNameOnDatatable; + } + + public static String getForeignKeyColumnNameOnDatatable(String name) { + return lookup.get(name).foreignKeyColumnNameOnDatatable; + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/StatusEnum.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/StatusEnum.java new file mode 100644 index 000000000..4700e28f3 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/StatusEnum.java @@ -0,0 +1,103 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.data; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.fineract.infrastructure.core.data.EnumOptionData; + +public enum StatusEnum { + + CREATE("create", 100), APPROVE("approve", 200), ACTIVATE("activate", 300), WITHDRAWN("withdraw", 400), REJECTED("reject", 500), CLOSE( + "close", 600), WRITE_OFF("write off", 601), RESCHEDULE("reschedule", 602), OVERPAY("overpay", 700); + + private String name; + + public Integer getCode() { + return code; + } + + private Integer code; + + private StatusEnum(String name, Integer code) { + + this.name = name; + this.code = code; + + } + + public static List getStatusList() { + + List data = new ArrayList(); + + for (StatusEnum status : StatusEnum.values()) { + data.add(new DatatableCheckStatusData(status.name, status.code)); + } + + return data; + + } + + public static StatusEnum fromInt(final Integer code) { + StatusEnum ret = null; + switch (code) { + case 100: + ret = StatusEnum.CREATE; + break; + case 200: + ret = StatusEnum.APPROVE; + break; + case 300: + ret = StatusEnum.ACTIVATE; + break; + case 400: + ret = StatusEnum.WITHDRAWN; + break; + case 500: + ret = StatusEnum.REJECTED; + break; + case 600: + ret = StatusEnum.CLOSE; + break; + case 601: + ret = StatusEnum.WRITE_OFF; + break; + case 602: + ret = StatusEnum.RESCHEDULE; + break; + case 700: + ret = StatusEnum.OVERPAY; + break; + default: + break; + } + return ret; + } + + public static EnumOptionData statusTypeEnum(final Integer id) { + return statusType(StatusEnum.fromInt(id)); + } + + public static EnumOptionData statusType(final StatusEnum statusType) { + final EnumOptionData optionData = new EnumOptionData(statusType.getCode().longValue(), statusType.name(), statusType.name()); + return optionData; + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/EntityDatatableChecks.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/EntityDatatableChecks.java new file mode 100644 index 000000000..9aef5b6de --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/EntityDatatableChecks.java @@ -0,0 +1,102 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.domain; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; + +@Entity +@Table(name = "m_entity_datatable_check") + +public class EntityDatatableChecks extends AbstractPersistableCustom { + + @Column(name = "application_table_name", nullable = false) + private String entity; + + @Column(name = "x_registered_table_name", nullable = false) + private String datatableName; + + @Column(name = "status_enum", nullable = false) + private Long status; + + @Column(name = "system_defined") + private boolean systemDefined = false; + + @Column(name = "product_id", nullable = true) + private Long productId; + + public EntityDatatableChecks() { + } + + public EntityDatatableChecks(final String entity, final String datatableName, final Long status, + final boolean systemDefined, final Long productId) { + + this.entity = entity; + this.status = status; + this.datatableName = datatableName; + this.systemDefined = systemDefined; + this.productId = productId; + } + + public static EntityDatatableChecks fromJson(final JsonCommand command) { + + final String entity = command.stringValueOfParameterNamed("entity"); + final Long status = command.longValueOfParameterNamed("status"); + final String datatableName = command.stringValueOfParameterNamed("datatableName"); + + boolean systemDefined = false; + if (command.parameterExists("systemDefined")) { + systemDefined = command.booleanObjectValueOfParameterNamed("systemDefined"); + } else { + systemDefined = false; + } + + Long productId = null; + if (command.parameterExists("productId")) { + productId = command.longValueOfParameterNamed("productId"); + } + + return new EntityDatatableChecks(entity, datatableName, status, systemDefined, productId); + + } + + public String getEntity() { + return this.entity; + } + + public Long getStatus() { + return this.status; + } + + public String getDatatableName() { + return this.datatableName; + } + + public boolean isSystemDefined() { + return this.systemDefined; + } + + public Long getProductId() { + return productId; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/EntityDatatableChecksRepository.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/EntityDatatableChecksRepository.java new file mode 100644 index 000000000..0560f8fe1 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/EntityDatatableChecksRepository.java @@ -0,0 +1,54 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.domain; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +public interface EntityDatatableChecksRepository + extends + JpaRepository, + JpaSpecificationExecutor { + + public List findByEntityAndStatus(String entityName, Long status); + + @Query("select t from EntityDatatableChecks t WHERE t.status =:status and t.entity=:entity and t.productId = :productId ") + public List findByEntityStatusAndProduct(@Param("entity") String entity, + @Param("status") Long status, @Param("productId") Long productId); + + @Query("select t from EntityDatatableChecks t WHERE t.status =:status and t.entity=:entity and t.productId IS NULL ") + public List findByEntityStatusAndNoProduct(@Param("entity") String entity, + @Param("status") Long status); + + @Query("select t from EntityDatatableChecks t WHERE t.status =:status " + + "and t.entity=:entity and t.datatableName = :datatableName AND t.productId = :productId") + public List findByEntityStatusAndDatatableIdAndProductId(@Param("entity") String entityName, + @Param("status") Long status, @Param("datatableName") String datatableName, + @Param("productId") Long productId); + + @Query("select t from EntityDatatableChecks t WHERE t.status =:status and t.entity=:entity " + + " and t.datatableName = :datatableName AND t.productId IS NULL") + public List findByEntityStatusAndDatatableIdAndNoProduct(@Param("entity") String entityName, + @Param("status") Long status, @Param("datatableName") String datatableName); + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/DatatabaleEntryRequiredException.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/DatatabaleEntryRequiredException.java new file mode 100644 index 000000000..7885d34d5 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/DatatabaleEntryRequiredException.java @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.exception; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.fineract.infrastructure.core.data.ApiParameterError; +import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; + +/** + * A {@link RuntimeException} thrown when datatable resources are not found. + */ +public class DatatabaleEntryRequiredException extends RuntimeException { + + public DatatabaleEntryRequiredException(final String datatableName) { + + final List dataValidationErrors = new ArrayList<>(); + + final String defaultMessage = "The datatable " + datatableName + + " needs to be filled in before the current action can be proceeded"; + final String messageCode = "error.msg.entry.required.in.datatable." + datatableName; + final ApiParameterError error = ApiParameterError.parameterError(messageCode, defaultMessage, "", 1, 0); + dataValidationErrors.add(error); + + throw new PlatformApiDataValidationException(dataValidationErrors); + } + +} \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckAlreadyExistsException.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckAlreadyExistsException.java new file mode 100644 index 000000000..e941f0528 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckAlreadyExistsException.java @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.exception; + +import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException; + +/** + * A {@link RuntimeException} thrown when datatable resources are not found. + */ +public class EntityDatatableCheckAlreadyExistsException extends AbstractPlatformDomainRuleException { + + public EntityDatatableCheckAlreadyExistsException(final String entityName, final Long status, + final String datatableName) { + super("error.msg.entityDatatableCheck.duplicate.entry", + "the entity datatable check for status: '" + status + "' and datatable name '" + datatableName + + "' on entity '" + entityName + "' already exist", + "status", "datatableName", "entity", status, datatableName, entityName); + } + + public EntityDatatableCheckAlreadyExistsException(final String entityName, long status, String datatableName, + long productId) { + super("error.msg.entityDatatableCheck.duplicate.entry", + "the entity datatable check for status: '" + status + "' and datatable name '" + datatableName + + "' on entity '" + entityName + "' and product id '" + productId + "' already exist", + "status", "datatableName", "entity", "productId", status, datatableName, entityName, productId); + } +} \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckNotAllowException.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckNotAllowException.java new file mode 100644 index 000000000..e04153c5c --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckNotAllowException.java @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.exception; + +import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; + +/** + * A {@link RuntimeException} thrown when datatable resources are not found. + */ +public class EntityDatatableCheckNotAllowException extends AbstractPlatformResourceNotFoundException { + + public EntityDatatableCheckNotAllowException(final String entityName) { + super("error.msg.entity.datatable.check.is.not.allowed", + "Entity Datatable check is not allow without a loan product id to :entity," + + " because there is already a check attached to the same entity with a loan product id", + entityName); + } + +} \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckNotSupportedException.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckNotSupportedException.java new file mode 100644 index 000000000..5380099cb --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckNotSupportedException.java @@ -0,0 +1,39 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.exception; + +import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; + +/** + * A {@link RuntimeException} thrown when datatable resources are not found. + */ +public class EntityDatatableCheckNotSupportedException extends AbstractPlatformResourceNotFoundException { + + public EntityDatatableCheckNotSupportedException(final String datatableName, final String entityName) { + super("error.msg.entity.datatable.check.combination.not.supported", + "Entity Datatable check on table "+datatableName+" is not supported for entity "+entityName, datatableName, + entityName); + } + + public EntityDatatableCheckNotSupportedException(final String entityName, final Long productId) { + super("error.msg.entity.datatable.check.combination.not.supported", + "Entity Datatable check on entity "+entityName+" is not supported with productId "+productId, entityName, + productId); + } +} \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableChecksNotFoundException.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableChecksNotFoundException.java new file mode 100644 index 000000000..0e61617a0 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableChecksNotFoundException.java @@ -0,0 +1,32 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.exception; + +import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; + +/** + * A {@link RuntimeException} thrown when report resources are not found. + */ +public class EntityDatatableChecksNotFoundException extends AbstractPlatformResourceNotFoundException { + + public EntityDatatableChecksNotFoundException(final Long id) { + super("error.msg.entity.datatable.check.not.found", + "Entity datatable check with identifier " + id + " does not exist", id); + } +} \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/handler/CreateEntityDatatableChecksCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/handler/CreateEntityDatatableChecksCommandHandler.java new file mode 100644 index 000000000..e7caed1af --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/handler/CreateEntityDatatableChecksCommandHandler.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.handler; + +import org.apache.fineract.commands.annotation.CommandType; +import org.apache.fineract.commands.handler.NewCommandSourceHandler; +import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@CommandType(entity = "ENTITY_DATATABLE_CHECK", action = "CREATE") +public class CreateEntityDatatableChecksCommandHandler implements NewCommandSourceHandler { + + private final EntityDatatableChecksWritePlatformService writePlatformService; + + @Autowired + public CreateEntityDatatableChecksCommandHandler( + final EntityDatatableChecksWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + + return this.writePlatformService.createCheck(command); + } +} \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/handler/DeleteEntityDatatableChecksCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/handler/DeleteEntityDatatableChecksCommandHandler.java new file mode 100644 index 000000000..f4301714c --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/handler/DeleteEntityDatatableChecksCommandHandler.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.handler; + +import org.apache.fineract.commands.annotation.CommandType; +import org.apache.fineract.commands.handler.NewCommandSourceHandler; +import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@CommandType(entity = "ENTITY_DATATABLE_CHECK", action = "DELETE") +public class DeleteEntityDatatableChecksCommandHandler implements NewCommandSourceHandler { + + private final EntityDatatableChecksWritePlatformService writePlatformService; + + @Autowired + public DeleteEntityDatatableChecksCommandHandler( + final EntityDatatableChecksWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public CommandProcessingResult processCommand(JsonCommand command) { + + return this.writePlatformService.deleteCheck(command.entityId()); + } +} \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksDataValidator.java new file mode 100644 index 000000000..81b54be78 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksDataValidator.java @@ -0,0 +1,98 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.service; + +import java.lang.reflect.Type; +import java.util.*; + +import org.apache.commons.lang.StringUtils; +import org.apache.fineract.infrastructure.core.data.ApiParameterError; +import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; +import org.apache.fineract.infrastructure.core.exception.InvalidJsonException; +import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; +import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; +import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.google.gson.JsonElement; +import com.google.gson.reflect.TypeToken; + +@Component +public final class EntityDatatableChecksDataValidator { + + /** + * The parameters supported for this command. + */ + private final Set supportedParameters = new HashSet<>( + Arrays.asList("entity", "datatableName", "status", "systemDefined", "productId")); + + private final FromJsonHelper fromApiJsonHelper; + + @Autowired + public EntityDatatableChecksDataValidator(final FromJsonHelper fromApiJsonHelper) { + this.fromApiJsonHelper = fromApiJsonHelper; + } + + public void validateForCreate(final String json) { + if (StringUtils.isBlank(json)) { + throw new InvalidJsonException(); + } + + final Type typeOfMap = new TypeToken>() { + }.getType(); + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters); + + final List dataValidationErrors = new ArrayList<>(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) + .resource("entityDatatableChecks"); + + final JsonElement element = this.fromApiJsonHelper.parse(json); + + final String entity = this.fromApiJsonHelper.extractStringNamed("entity", element); + baseDataValidator.reset().parameter("entity").value(entity).notBlank() + .isOneOfTheseStringValues(EntityTables.getEntitiesList()); + + final Integer status = this.fromApiJsonHelper.extractIntegerSansLocaleNamed("status", element); + final Object[] entityTablesStatuses = EntityTables.getStatus(entity); + + baseDataValidator.reset().parameter("status").value(status).isOneOfTheseValues(entityTablesStatuses); + + final String datatableName = this.fromApiJsonHelper.extractStringNamed("datatableName", element); + baseDataValidator.reset().parameter("datatableName").value(datatableName).notBlank(); + + if (this.fromApiJsonHelper.parameterExists("systemDefined", element)) { + final String systemDefined = this.fromApiJsonHelper.extractStringNamed("systemDefined", element); + baseDataValidator.reset().parameter("systemDefined").value(systemDefined).validateForBooleanValue(); + } + + if (this.fromApiJsonHelper.parameterExists("productId", element)) { + final long productId = this.fromApiJsonHelper.extractLongNamed("productId", element); + baseDataValidator.reset().parameter("productId").value(productId).integerZeroOrGreater(); + } + + throwExceptionIfValidationWarningsExist(dataValidationErrors); + } + + private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { + if (!dataValidationErrors.isEmpty()) { + throw new PlatformApiDataValidationException(dataValidationErrors); + } + } +} \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadPlatformServiceImpl.java new file mode 100644 index 000000000..31f58a2ee --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadPlatformServiceImpl.java @@ -0,0 +1,217 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.service; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.infrastructure.core.domain.JdbcSupport; +import org.apache.fineract.infrastructure.core.service.Page; +import org.apache.fineract.infrastructure.core.service.PaginationHelper; +import org.apache.fineract.infrastructure.core.service.RoutingDataSource; +import org.apache.fineract.infrastructure.core.service.SearchParameters; +import org.apache.fineract.infrastructure.dataqueries.data.DatatableCheckStatusData; +import org.apache.fineract.infrastructure.dataqueries.data.DatatableChecksData; +import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; +import org.apache.fineract.infrastructure.dataqueries.data.EntityDataTableChecksData; +import org.apache.fineract.infrastructure.dataqueries.data.EntityDataTableChecksTemplateData; +import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; +import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; +import org.apache.fineract.infrastructure.dataqueries.domain.EntityDatatableChecks; +import org.apache.fineract.infrastructure.dataqueries.domain.EntityDatatableChecksRepository; +import org.apache.fineract.portfolio.loanproduct.data.LoanProductData; +import org.apache.fineract.portfolio.loanproduct.service.LoanProductReadPlatformService; +import org.apache.fineract.portfolio.savings.data.SavingsProductData; +import org.apache.fineract.portfolio.savings.service.SavingsProductReadPlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Service; + +@Service +public class EntityDatatableChecksReadPlatformServiceImpl implements EntityDatatableChecksReadService { + + private final JdbcTemplate jdbcTemplate; + private final RegisterDataTableMapper registerDataTableMapper; + private final EntityDataTableChecksMapper entityDataTableChecksMapper; + private final EntityDatatableChecksRepository entityDatatableChecksRepository; + private final ReadWriteNonCoreDataService readWriteNonCoreDataService; + private final LoanProductReadPlatformService loanProductReadPlatformService; + private final SavingsProductReadPlatformService savingsProductReadPlatformService; + private final PaginationHelper paginationHelper = new PaginationHelper<>(); + + @Autowired + public EntityDatatableChecksReadPlatformServiceImpl(final RoutingDataSource dataSource, + final LoanProductReadPlatformService loanProductReadPlatformService, + final SavingsProductReadPlatformService savingsProductReadPlatformService, + final EntityDatatableChecksRepository entityDatatableChecksRepository, + final ReadWriteNonCoreDataService readWriteNonCoreDataService) { + + this.jdbcTemplate = new JdbcTemplate(dataSource); + this.registerDataTableMapper = new RegisterDataTableMapper(); + this.entityDataTableChecksMapper = new EntityDataTableChecksMapper(); + this.loanProductReadPlatformService = loanProductReadPlatformService; + this.savingsProductReadPlatformService = savingsProductReadPlatformService; + this.entityDatatableChecksRepository = entityDatatableChecksRepository; + this.readWriteNonCoreDataService = readWriteNonCoreDataService; + } + + @Override + public Page retrieveAll(SearchParameters searchParameters, final Long status, final String entity, + final Long productId) { + final StringBuilder sqlBuilder = new StringBuilder(200); + sqlBuilder.append("select SQL_CALC_FOUND_ROWS "); + sqlBuilder.append(this.entityDataTableChecksMapper.schema()); + + if (status != null || entity != null || productId != null) { + sqlBuilder.append(" where "); + } + + if (status != null) { + sqlBuilder.append(" status_enum = " + status); + } + + if (entity != null) { + sqlBuilder.append(" and t.application_table_name = '" + entity + "'"); + } + + if (productId != null) { + sqlBuilder.append(" and t.product_id = " + productId); + } + if (searchParameters.isLimited()) { + sqlBuilder.append(" limit ").append(searchParameters.getLimit()); + if (searchParameters.isOffset()) { + sqlBuilder.append(" offset ").append(searchParameters.getOffset()); + } + } + final String sqlCountRows = "SELECT FOUND_ROWS()"; + return this.paginationHelper.fetchPage(jdbcTemplate, sqlCountRows, sqlBuilder.toString(), new Object[] {}, + entityDataTableChecksMapper); + + } + + @Override + public List retrieveTemplates(final Long status, final String entity, final Long productId) { + + List tableRequiredBeforeAction = null; + if (productId != null) { + tableRequiredBeforeAction = this.entityDatatableChecksRepository.findByEntityStatusAndProduct(entity, status, productId); + } + + if (tableRequiredBeforeAction == null || tableRequiredBeforeAction.size() < 1) { + tableRequiredBeforeAction = this.entityDatatableChecksRepository.findByEntityStatusAndNoProduct(entity, status); + } + if (tableRequiredBeforeAction != null && tableRequiredBeforeAction.size() > 0) { + List ret = new ArrayList<>(); + for (EntityDatatableChecks t : tableRequiredBeforeAction) { + ret.add(this.readWriteNonCoreDataService.retrieveDatatable(t.getDatatableName())); + } + return ret; + } + return null; + } + + @Override + public EntityDataTableChecksTemplateData retrieveTemplate() { + + List dataTables = getDataTables(); + List entities = EntityTables.getEntitiesList(); + List statusClient = getStatusList(EntityTables.getStatus("m_client")); + List statusLoan = getStatusList(EntityTables.getStatus("m_loan")); + List statusGroup = getStatusList(EntityTables.getStatus("m_group")); + List statusSavings = getStatusList(EntityTables.getStatus("m_savings_account")); + + Collection loanProductDatas = this.loanProductReadPlatformService.retrieveAllLoanProductsForLookup(true); + Collection savingsProductDatas = this.savingsProductReadPlatformService.retrieveAllForLookup(); + + return new EntityDataTableChecksTemplateData(entities, statusClient, statusGroup, statusSavings, statusLoan, dataTables, + loanProductDatas, savingsProductDatas); + + } + + private List getStatusList(Integer[] statuses) { + List ret = new ArrayList<>(); + if (statuses != null) { + for (Integer status : statuses) { + StatusEnum statusEnum = StatusEnum.fromInt(status); + ret.add(new DatatableCheckStatusData(statusEnum.name(), statusEnum.getCode())); + } + } + return ret; + } + + private List getDataTables() { + final String sql = "select " + this.registerDataTableMapper.schema(); + + return this.jdbcTemplate.query(sql, this.registerDataTableMapper); + } + + protected static final class RegisterDataTableMapper implements RowMapper { + + @Override + public DatatableChecksData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + + final String entity = rs.getString("entity"); + final String tableName = rs.getString("tableName"); + + return new DatatableChecksData(entity, tableName); + } + + public String schema() { + return " t.application_table_name as entity, t.registered_table_name as tableName " + " from x_registered_table t " + + " where application_table_name IN( 'm_client','m_group','m_savings_account','m_loan')"; + } + } + + protected static final class EntityDataTableChecksMapper implements RowMapper { + + @Override + public EntityDataTableChecksData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + + final Long id = JdbcSupport.getLong(rs, "id"); + final String entity = rs.getString("entity"); + final Long status = rs.getLong("status"); + EnumOptionData statusEnum = null; + if (status != null) { + statusEnum = StatusEnum.statusTypeEnum(status.intValue()); + } + final String datatableName = rs.getString("datatableName"); + final boolean systemDefined = rs.getBoolean("systemDefined"); + final Long productId = JdbcSupport.getLong(rs, "productId"); + final String productName = rs.getString("productName"); + + return new EntityDataTableChecksData(id, entity, statusEnum, datatableName, systemDefined, productId, productName); + } + + public String schema() { + return " t.id as id, " + "t.application_table_name as entity, " + "t.status_enum as status, " + + "t.system_defined as systemDefined, " + "t.x_registered_table_name as datatableName, " + + "t.product_id as productId, " + "(CASE t.application_table_name " + "WHEN 'm_loan' THEN lp.name " + + "WHEN 'm_savings_account' THEN sp.name " + "ELSE NULL " + "END) as productName " + + "from m_entity_datatable_check as t " + + "left join m_product_loan lp on lp.id = t.product_id and t.application_table_name = 'm_loan' " + + "left join m_savings_product sp on sp.id = t.product_id and t.application_table_name = 'm_savings_account' "; + } + } + +} \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadService.java new file mode 100644 index 000000000..3b1b029d6 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadService.java @@ -0,0 +1,37 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.service; + +import java.util.List; + +import org.apache.fineract.infrastructure.core.service.Page; +import org.apache.fineract.infrastructure.core.service.SearchParameters; +import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; +import org.apache.fineract.infrastructure.dataqueries.data.EntityDataTableChecksData; +import org.apache.fineract.infrastructure.dataqueries.data.EntityDataTableChecksTemplateData; + +public interface EntityDatatableChecksReadService { + + EntityDataTableChecksTemplateData retrieveTemplate(); + + List retrieveTemplates(Long status, String entity, Long productId); + + Page retrieveAll(SearchParameters searchParameters, Long status, String entity, Long productLoanId); + +} \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksWritePlatformService.java new file mode 100644 index 000000000..d20b48eab --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksWritePlatformService.java @@ -0,0 +1,34 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.service; + +import com.google.gson.JsonArray; +import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; + +public interface EntityDatatableChecksWritePlatformService { + + CommandProcessingResult createCheck(JsonCommand command); + CommandProcessingResult deleteCheck(final Long entityDatatableCheckId); + void runTheCheck(final Long entityId, final String entityName, final Long statusCode, String foreignKeyColumn); + void runTheCheckForProduct(final Long entityId, final String entityName, final Long statusCode, + String foreignKeyColumn, long productLoanId); + boolean saveDatatables(Long status, String entity, Long entityId, Long productId, JsonArray data); + +} \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksWritePlatformServiceImpl.java new file mode 100644 index 000000000..34f13126d --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksWritePlatformServiceImpl.java @@ -0,0 +1,315 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.dataqueries.service; + +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.PersistenceException; + +import org.apache.commons.lang.exception.ExceptionUtils; +import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; +import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.data.ApiParameterError; +import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; +import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; +import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; +import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; +import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; +import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; +import org.apache.fineract.infrastructure.dataqueries.domain.EntityDatatableChecks; +import org.apache.fineract.infrastructure.dataqueries.domain.EntityDatatableChecksRepository; +import org.apache.fineract.infrastructure.dataqueries.exception.*; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.apache.fineract.portfolio.loanproduct.service.LoanProductReadPlatformService; +import org.apache.fineract.portfolio.savings.service.SavingsProductReadPlatformService; +import org.apache.fineract.useradministration.domain.AppUser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +@Service +public class EntityDatatableChecksWritePlatformServiceImpl implements EntityDatatableChecksWritePlatformService { + + private final static Logger logger = LoggerFactory.getLogger(EntityDatatableChecksWritePlatformServiceImpl.class); + + private final PlatformSecurityContext context; + private final EntityDatatableChecksDataValidator fromApiJsonDeserializer; + private final EntityDatatableChecksRepository entityDatatableChecksRepository; + private final ReadWriteNonCoreDataService readWriteNonCoreDataService; + private final LoanProductReadPlatformService loanProductReadPlatformService; + private final SavingsProductReadPlatformService savingsProductReadPlatformService; + private final FromJsonHelper fromApiJsonHelper; + private final ConfigurationDomainService configurationDomainService; + + @Autowired + public EntityDatatableChecksWritePlatformServiceImpl(final PlatformSecurityContext context, + final EntityDatatableChecksDataValidator fromApiJsonDeserializer, + final EntityDatatableChecksRepository entityDatatableChecksRepository, + final ReadWriteNonCoreDataService readWriteNonCoreDataService, + final LoanProductReadPlatformService loanProductReadPlatformService, + final SavingsProductReadPlatformService savingsProductReadPlatformService, + final FromJsonHelper fromApiJsonHelper, + final ConfigurationDomainService configurationDomainService) { + this.context = context; + this.fromApiJsonDeserializer = fromApiJsonDeserializer; + this.entityDatatableChecksRepository = entityDatatableChecksRepository; + this.readWriteNonCoreDataService = readWriteNonCoreDataService; + this.loanProductReadPlatformService = loanProductReadPlatformService; + this.savingsProductReadPlatformService = savingsProductReadPlatformService; + this.fromApiJsonHelper = fromApiJsonHelper; + this.configurationDomainService = configurationDomainService; + } + + @Transactional + @Override + public CommandProcessingResult createCheck(final JsonCommand command) { + + try { + this.context.authenticatedUser(); + + this.fromApiJsonDeserializer.validateForCreate(command.json()); + + // check if the datatable is linked to the entity + + String datatableName = command.stringValueOfParameterNamed("datatableName"); + DatatableData datatableData = this.readWriteNonCoreDataService.retrieveDatatable(datatableName); + + if (datatableData == null) { + throw new DatatableNotFoundException(datatableName); + } + + final String entity = command.stringValueOfParameterNamed("entity"); + final String foreignKeyColumnName = EntityTables.getForeignKeyColumnNameOnDatatable(entity); + final boolean columnExist = datatableData.hasColumn(foreignKeyColumnName); + + logger.info(datatableData.getRegisteredTableName() + "has column " + foreignKeyColumnName + " ? " + + columnExist); + + if (!columnExist) { + throw new EntityDatatableCheckNotSupportedException(datatableData.getRegisteredTableName(), entity); + } + + final Long productId = command.longValueOfParameterNamed("productId"); + final Long status = command.longValueOfParameterNamed("status"); + + + List entityDatatableCheck = null; + if (productId == null) { + entityDatatableCheck = this.entityDatatableChecksRepository + .findByEntityStatusAndDatatableIdAndNoProduct(entity, status, datatableName); + if (!entityDatatableCheck.isEmpty()) { + throw new EntityDatatableCheckAlreadyExistsException(entity, status, datatableName); + } + } else { + if (entity.equals("m_loan")) { + // if invalid loan product id, throws exception + this.loanProductReadPlatformService.retrieveLoanProduct(productId); + } else if (entity.equals("m_savings_account")) { + // if invalid savings product id, throws exception + this.savingsProductReadPlatformService.retrieveOne(productId); + } else { + throw new EntityDatatableCheckNotSupportedException(entity, productId); + } + entityDatatableCheck = this.entityDatatableChecksRepository + .findByEntityStatusAndDatatableIdAndProductId(entity, status, datatableName, productId); + if (!entityDatatableCheck.isEmpty()) { + throw new EntityDatatableCheckAlreadyExistsException(entity, status, datatableName, productId); + } + } + + final EntityDatatableChecks check = EntityDatatableChecks.fromJson(command); + + this.entityDatatableChecksRepository.saveAndFlush(check); + + return new CommandProcessingResultBuilder() // + .withCommandId(command.commandId()) // + .withEntityId(check.getId()) // + .build(); + } catch (final DataAccessException e) { + handleReportDataIntegrityIssues(command, e.getMostSpecificCause(), e); + return CommandProcessingResult.empty(); + }catch (final PersistenceException dve) { + Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ; + handleReportDataIntegrityIssues(command, throwable, dve); + return CommandProcessingResult.empty(); + } + } + + public void runTheCheck(final Long entityId, final String entityName, final Long statusCode, + String foreignKeyColumn) { + final List tableRequiredBeforeClientActivation = entityDatatableChecksRepository + .findByEntityAndStatus(entityName, statusCode); + + if (tableRequiredBeforeClientActivation != null) { + List reqDatatables = new ArrayList<>(); + for (EntityDatatableChecks t : tableRequiredBeforeClientActivation) { + + final String datatableName = t.getDatatableName(); + final Long countEntries = readWriteNonCoreDataService.countDatatableEntries(datatableName, entityId, + foreignKeyColumn); + + logger.info("The are " + countEntries + " entries in the table " + datatableName); + if (countEntries.intValue() == 0) { + reqDatatables.add(datatableName); + } + } + if(reqDatatables.size() > 0){ + throw new DatatabaleEntryRequiredException(reqDatatables.toString()); + } + } + + } + + public void runTheCheckForProduct(final Long entityId, final String entityName, final Long statusCode, + String foreignKeyColumn, long productId) { + List tableRequiredBeforAction = entityDatatableChecksRepository + .findByEntityStatusAndProduct(entityName, statusCode, productId); + + if (tableRequiredBeforAction == null || tableRequiredBeforAction.size() < 1) { + tableRequiredBeforAction = entityDatatableChecksRepository.findByEntityStatusAndNoProduct(entityName, + statusCode); + } + if (tableRequiredBeforAction != null) { + List reqDatatables = new ArrayList<>(); + for (EntityDatatableChecks t : tableRequiredBeforAction) { + + final String datatableName = t.getDatatableName(); + final Long countEntries = readWriteNonCoreDataService.countDatatableEntries(datatableName, entityId, + foreignKeyColumn); + + logger.info("The are " + countEntries + " entries in the table " + datatableName); + if (countEntries.intValue() == 0) { + reqDatatables.add(datatableName); + } + } + if(reqDatatables.size() > 0){ + throw new DatatabaleEntryRequiredException(reqDatatables.toString()); + } + } + + } + + @Transactional + @Override + public boolean saveDatatables(final Long status, final String entity, final Long entityId, + final Long productId, final JsonArray datatableDatas) { + final AppUser user = this.context.authenticatedUser(); + boolean isMakerCheckerEnabled = false; + if(datatableDatas != null && datatableDatas.size() > 0){ + for(JsonElement element : datatableDatas){ + final String datatableName = this.fromApiJsonHelper.extractStringNamed("registeredTableName",element); + final JsonObject datatableData = this.fromApiJsonHelper.extractJsonObjectNamed("data", element); + + if(datatableName == null || datatableData == null){ + final ApiParameterError error = ApiParameterError.generalError("registeredTableName.and.data.parameters.must.be.present.in.each.list.items.in.datatables", + "registeredTableName and data parameters must be present in each list items in datatables"); + List errors = new ArrayList<>(); + errors.add(error); + throw new PlatformApiDataValidationException(errors); + } + final String taskPermissionName = "CREATE_" + datatableName; + user.validateHasPermissionTo(taskPermissionName); + if(this.configurationDomainService.isMakerCheckerEnabledForTask(taskPermissionName)){ + isMakerCheckerEnabled = true; + } + try{ + this.readWriteNonCoreDataService.createNewDatatableEntry(datatableName, entityId, datatableData.toString()); + } catch(PlatformApiDataValidationException e){ + List errors = e.getErrors(); + for(ApiParameterError error : e.getErrors()){ + error.setParameterName("datatables."+datatableName+"."+error.getParameterName()); + } + throw e; + } + } + } + return isMakerCheckerEnabled; + } + + private List getDatatableNames(Long status, String entity, Long productId) { + List ret = new ArrayList<>(); + List tableRequiredBeforeAction = null; + if(productId != null){ + tableRequiredBeforeAction = this.entityDatatableChecksRepository + .findByEntityStatusAndProduct(entity, status, productId); + } + + if (tableRequiredBeforeAction == null || tableRequiredBeforeAction.size() < 1) { + tableRequiredBeforeAction = this.entityDatatableChecksRepository.findByEntityStatusAndNoProduct(entity, + status); + } + if (tableRequiredBeforeAction != null && tableRequiredBeforeAction.size() > 0) { + for (EntityDatatableChecks t : tableRequiredBeforeAction) { + ret.add(t.getDatatableName()); + } + } + return ret; + } + + @Transactional + @Override + public CommandProcessingResult deleteCheck(final Long entityDatatableCheckId) { + + final EntityDatatableChecks check = this.entityDatatableChecksRepository.findOne(entityDatatableCheckId); + if (check == null) { + throw new EntityDatatableChecksNotFoundException(entityDatatableCheckId); + } + + this.entityDatatableChecksRepository.delete(check); + + return new CommandProcessingResultBuilder() // + .withEntityId(entityDatatableCheckId) // + .build(); + } + + /* + * Guaranteed to throw an exception no matter what the data integrity issue + * is. + */ + private void handleReportDataIntegrityIssues(final JsonCommand command, final Throwable realCause, final Exception dae) { + + if (realCause.getMessage().contains("FOREIGN KEY (`x_registered_table_name`)")) { + final String datatableName = command.stringValueOfParameterNamed("datatableName"); + throw new PlatformDataIntegrityException("error.msg.entityDatatableCheck.foreign.key.constraint", + "datatable with name '" + datatableName + "' do not exist", "datatableName", datatableName); + } + + if (realCause.getMessage().contains("unique_entity_check")) { + final String datatableName = command.stringValueOfParameterNamed("datatableName"); + final long status = command.longValueOfParameterNamed("status"); + final String entity = command.stringValueOfParameterNamed("entity"); + final long productId = command.longValueOfParameterNamed("productId"); + throw new EntityDatatableCheckAlreadyExistsException(entity, status, datatableName, productId); + } + + logger.error(dae.getMessage(), dae); + throw new PlatformDataIntegrityException("error.msg.report.unknown.data.integrity.issue", + "Unknown data integrity issue with resource: " + realCause.getMessage()); + } + +} \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataService.java index 22529a3cb..e7f63645c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataService.java @@ -54,6 +54,8 @@ public interface ReadWriteNonCoreDataService { CommandProcessingResult createNewDatatableEntry(String datatable, Long appTableId, JsonCommand command); + CommandProcessingResult createNewDatatableEntry(String datatable, Long appTableId, String json); + CommandProcessingResult createPPIEntry(String datatable, Long appTableId, JsonCommand command); CommandProcessingResult updateDatatableEntryOneToOne(String datatable, Long appTableId, JsonCommand command); @@ -68,4 +70,5 @@ public interface ReadWriteNonCoreDataService { String getDataTableName(String Url); + Long countDatatableEntries(String datatableName,Long appTableId,String foreignKeyColumn); } \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java index c40b94901..e0a069679 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java @@ -20,13 +20,7 @@ package org.apache.fineract.infrastructure.dataqueries.service; import java.lang.reflect.Type; import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; +import java.util.*; import javax.persistence.PersistenceException; import javax.sql.DataSource; @@ -50,11 +44,7 @@ import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper; import org.apache.fineract.infrastructure.core.service.RoutingDataSource; import org.apache.fineract.infrastructure.dataqueries.api.DataTableApiConstant; -import org.apache.fineract.infrastructure.dataqueries.data.DataTableValidator; -import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; -import org.apache.fineract.infrastructure.dataqueries.data.GenericResultsetData; -import org.apache.fineract.infrastructure.dataqueries.data.ResultsetColumnHeaderData; -import org.apache.fineract.infrastructure.dataqueries.data.ResultsetRowData; +import org.apache.fineract.infrastructure.dataqueries.data.*; import org.apache.fineract.infrastructure.dataqueries.exception.DatatableNotFoundException; import org.apache.fineract.infrastructure.dataqueries.exception.DatatableSystemErrorException; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; @@ -359,7 +349,12 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ @Transactional @Override public CommandProcessingResult createNewDatatableEntry(final String dataTableName, final Long appTableId, final JsonCommand command) { + return createNewDatatableEntry(dataTableName, appTableId, command.json()); + } + @Transactional + @Override + public CommandProcessingResult createNewDatatableEntry(final String dataTableName, final Long appTableId, final String json) { try { final String appTable = queryForApplicationTableName(dataTableName); final CommandProcessingResult commandProcessingResult = checkMainResourceExistsWithinScope(appTable, appTableId); @@ -367,7 +362,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ final List columnHeaders = this.genericDataService.fillResultsetColumnHeaders(dataTableName); final Type typeOfMap = new TypeToken>() {}.getType(); - final Map dataParams = this.fromJsonHelper.extractDataMap(typeOfMap, command.json()); + final Map dataParams = this.fromJsonHelper.extractDataMap(typeOfMap, json); final String sql = getAddSql(columnHeaders, dataTableName, getFKField(appTable), appTableId, dataParams); @@ -378,29 +373,32 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ } catch (final DataAccessException dve) { final Throwable cause = dve.getCause() ; final Throwable realCause = dve.getMostSpecificCause(); - if (realCause.getMessage() - .contains("Duplicate entry") || cause.getMessage() - .contains("Duplicate entry")) { throw new PlatformDataIntegrityException( - "error.msg.datatable.entry.duplicate", "An entry already exists for datatable `" + dataTableName - + "` and application table with identifier `" + appTableId + "`.", - "dataTableName", dataTableName, appTableId); } + if (realCause.getMessage().contains("Duplicate entry") || cause.getMessage().contains("Duplicate entry")) { + throw new PlatformDataIntegrityException("error.msg.datatable.entry.duplicate", "An entry already exists for datatable `" + + dataTableName + "` and application table with identifier `" + appTableId + "`.", "dataTableName", dataTableName, + appTableId); + } else if (realCause.getMessage().contains("doesn't have a default value") + || cause.getMessage().contains("doesn't have a default value")) { throw new PlatformDataIntegrityException( + "error.msg.datatable.no.value.provided.for.required.fields", "No values provided for the datatable `" + dataTableName + + "` and application table with identifier `" + appTableId + "`.", "dataTableName", dataTableName, appTableId); } logAsErrorUnexpectedDataIntegrityException(dve); throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue", "Unknown data integrity issue with resource."); - }catch(final PersistenceException e) { - final Throwable cause = e.getCause() ; - if (cause.getMessage() - .contains("Duplicate entry")) { - throw new PlatformDataIntegrityException( - "error.msg.datatable.entry.duplicate", "An entry already exists for datatable `" + dataTableName - + "` and application table with identifier `" + appTableId + "`.", - "dataTableName", dataTableName, appTableId); } + } catch (final PersistenceException e) { + final Throwable cause = e.getCause(); + if (cause.getMessage().contains("Duplicate entry")) { + throw new PlatformDataIntegrityException("error.msg.datatable.entry.duplicate", "An entry already exists for datatable `" + + dataTableName + "` and application table with identifier `" + appTableId + "`.", "dataTableName", dataTableName, + appTableId); + } else if (cause.getMessage().contains("doesn't have a default value")) { throw new PlatformDataIntegrityException( + "error.msg.datatable.no.value.provided.for.required.fields", "No values provided for the datatable `" + dataTableName + + "` and application table with identifier `" + appTableId + "`.", "dataTableName", dataTableName, appTableId); } logAsErrorUnexpectedDataIntegrityException(e); throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue", "Unknown data integrity issue with resource."); - + } } @@ -1722,4 +1720,14 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ return true; } + + @Override + public Long countDatatableEntries(final String datatableName, final Long appTableId, String foreignKeyColumn) { + + final String sqlString = "SELECT COUNT(`" + foreignKeyColumn + "`) FROM `" + datatableName + "` WHERE `" + foreignKeyColumn + "`=" + + appTableId; + final Long count = this.jdbcTemplate.queryForObject(sqlString, Long.class); + return count; + } + } \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientApiConstants.java index e4f3ef102..fe5ec6483 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientApiConstants.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientApiConstants.java @@ -177,16 +177,18 @@ public class ClientApiConstants { public static final String officeOptionsParamName = "officeOptions"; public static final String staffOptionsParamName = "staffOptions"; + public static final String datatables = "datatables"; + public static final Set CLIENT_CREATE_REQUEST_DATA_PARAMETERS = new HashSet<>( Arrays.asList(address,localeParamName, dateFormatParamName, groupIdParamName, accountNoParamName, externalIdParamName, mobileNoParamName, firstnameParamName, middlenameParamName, lastnameParamName, fullnameParamName, officeIdParamName, activeParamName, activationDateParamName, staffIdParamName, submittedOnDateParamName, savingsProductIdParamName, dateOfBirthParamName, genderIdParamName, clientTypeIdParamName, clientClassificationIdParamName, - clientNonPersonDetailsParamName, displaynameParamName, legalFormIdParamName)); + clientNonPersonDetailsParamName, displaynameParamName, legalFormIdParamName, datatables)); public static final Set CLIENT_NON_PERSON_CREATE_REQUEST_DATA_PARAMETERS = new HashSet<>( Arrays.asList(address,localeParamName, dateFormatParamName, incorpNumberParamName, remarksParamName, incorpValidityTillParamName, - constitutionIdParamName, mainBusinessLineIdParamName)); + constitutionIdParamName, mainBusinessLineIdParamName, datatables)); public static final Set CLIENT_UPDATE_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName, dateFormatParamName, accountNoParamName, externalIdParamName, mobileNoParamName, firstnameParamName, middlenameParamName, diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientData.java index bcba0fc8b..913ac1739 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientData.java @@ -27,6 +27,7 @@ import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.fineract.infrastructure.codes.data.CodeValueData; import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; import org.apache.fineract.organisation.office.data.OfficeData; import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.portfolio.address.data.AddressData; @@ -101,12 +102,14 @@ final public class ClientData implements Comparable { private final Boolean isAddressEnabled; + private final List datatables; + public static ClientData template(final Long officeId, final LocalDate joinedDate, final Collection officeOptions, final Collection staffOptions, final Collection narrations, final Collection genderOptions, final Collection savingProductOptions, - final Collection clientTypeOptions, final Collection clientClassificationOptions, - final Collection clientNonPersonConstitutionOptions, final Collection clientNonPersonMainBusinessLineOptions, - final List clientLegalFormOptions, final AddressData address,final Boolean isAddressEnabled) { + final Collection clientTypeOptions, final Collection clientClassificationOptions, final Collection clientNonPersonConstitutionOptions, + final Collection clientNonPersonMainBusinessLineOptions, final List clientLegalFormOptions, final AddressData address, + final Boolean isAddressEnabled, final List datatables) { final String accountNo = null; final EnumOptionData status = null; final CodeValueData subStatus = null; @@ -141,7 +144,7 @@ final public class ClientData implements Comparable { staffName, officeOptions, groups, staffOptions, narrations, genderOptions, timeline, savingProductOptions, savingsProductId, savingsProductName, savingsAccountId, savingAccountOptions, clientType, clientClassification, clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, - clientNonPersonDetails, clientLegalFormOptions, legalForm,address, isAddressEnabled); + clientNonPersonDetails, clientLegalFormOptions, legalForm,address, isAddressEnabled, datatables); } @@ -156,7 +159,7 @@ final public class ClientData implements Comparable { clientData.savingsProductName, clientData.savingsAccountId, clientData.savingAccountOptions, clientData.clientType, clientData.clientClassification, templateData.clientTypeOptions, templateData.clientClassificationOptions, templateData.clientNonPersonConstitutionOptions, templateData.clientNonPersonMainBusinessLineOptions, clientData.clientNonPersonDetails, - templateData.clientLegalFormOptions, clientData.legalForm, clientData.address,clientData.isAddressEnabled); + templateData.clientLegalFormOptions, clientData.legalForm, clientData.address,clientData.isAddressEnabled, null); } @@ -172,7 +175,7 @@ final public class ClientData implements Comparable { clientData.savingsProductName, clientData.savingsAccountId, savingAccountOptions, clientData.clientType, clientData.clientClassification, clientData.clientTypeOptions, clientData.clientClassificationOptions, clientData.clientNonPersonConstitutionOptions, clientData.clientNonPersonMainBusinessLineOptions, clientData.clientNonPersonDetails, - clientData.clientLegalFormOptions, clientData.legalForm,clientData.address, clientData.isAddressEnabled); + clientData.clientLegalFormOptions, clientData.legalForm,clientData.address, clientData.isAddressEnabled, null); } @@ -186,7 +189,7 @@ final public class ClientData implements Comparable { clientData.savingAccountOptions, clientData.clientType, clientData.clientClassification, clientData.clientTypeOptions, clientData.clientClassificationOptions, clientData.clientNonPersonConstitutionOptions, clientData.clientNonPersonMainBusinessLineOptions, clientData.clientNonPersonDetails, clientData.clientLegalFormOptions, clientData.legalForm,clientData.address, - clientData.isAddressEnabled); + clientData.isAddressEnabled, null); } @@ -230,7 +233,7 @@ final public class ClientData implements Comparable { staffName, allowedOffices, groups, staffOptions, closureReasons, genderOptions, timeline, savingProductOptions, savingsProductId, savingsProductName, savingsAccountId, savingAccountOptions, clientType, clientClassification, clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, - clientNonPerson, clientLegalFormOptions, legalForm,null,null); + clientNonPerson, clientLegalFormOptions, legalForm,null,null, null); } public static ClientData lookup(final Long id, final String displayName, final Long officeId, final String officeName) { @@ -276,7 +279,7 @@ final public class ClientData implements Comparable { staffName, allowedOffices, groups, staffOptions, closureReasons, genderOptions, timeline, savingProductOptions, savingsProductId, savingsProductName, savingsAccountId, savingAccountOptions, clientType, clientClassification, clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, - clientNonPerson, clientLegalFormOptions, legalForm,null,null); + clientNonPerson, clientLegalFormOptions, legalForm,null,null, null); } @@ -304,7 +307,7 @@ final public class ClientData implements Comparable { staffName, allowedOffices, groups, staffOptions, closureReasons, genderOptions, timeline, savingProductOptions, savingsProductId, savingsProductName, savingsAccountId, null, clientType, clientClassification, clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, clientNonPerson, - clientLegalFormOptions, legalForm,null,null); + clientLegalFormOptions, legalForm,null,null, null); } @@ -321,7 +324,8 @@ final public class ClientData implements Comparable { final CodeValueData clientClassification, final Collection clientTypeOptions, final Collection clientClassificationOptions, final Collection clientNonPersonConstitutionOptions, final Collection clientNonPersonMainBusinessLineOptions, final ClientNonPersonData clientNonPerson, - final List clientLegalFormOptions, final EnumOptionData legalForm,final AddressData address, final Boolean isAddressEnabled) { + final List clientLegalFormOptions, final EnumOptionData legalForm, final AddressData address, + final Boolean isAddressEnabled, final List datatables) { this.accountNo = accountNo; this.status = status; if (status != null) { @@ -382,7 +386,8 @@ final public class ClientData implements Comparable { this.clientNonPersonDetails = clientNonPerson; this.address = address; - this.isAddressEnabled = isAddressEnabled; + this.isAddressEnabled = isAddressEnabled; + this.datatables = datatables; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientDataValidator.java index 663491659..4c2f538c8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientDataValidator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientDataValidator.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import com.google.gson.JsonArray; import org.apache.commons.lang.StringUtils; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.ApiParameterError; @@ -94,6 +95,13 @@ public final class ClientDataValidator { final Long savingsProductId = this.fromApiJsonHelper.extractLongNamed(ClientApiConstants.savingsProductIdParamName, element); baseDataValidator.reset().parameter(ClientApiConstants.savingsProductIdParamName).value(savingsProductId).ignoreIfNull() .longGreaterThanZero(); + /*if (savingsProductId != null && this.fromApiJsonHelper.parameterExists(ClientApiConstants.datatables, element)) { + final JsonArray datatables = this.fromApiJsonHelper.extractJsonArrayNamed(ClientApiConstants.datatables, element); + if (datatables.size() > 0) { + baseDataValidator.reset().parameter(ClientApiConstants.savingsProductIdParamName).value(savingsProductId) + .failWithCodeNoParameterAddedToErrorCode("should.not.be.used.with.datatables.parameter"); + } + }*/ } if (isFullnameProvided(element) || isIndividualNameProvided(element)) { @@ -154,6 +162,10 @@ public final class ClientDataValidator { final LocalDate joinedDate = this.fromApiJsonHelper.extractLocalDateNamed(ClientApiConstants.activationDateParamName, element); baseDataValidator.reset().parameter(ClientApiConstants.activationDateParamName).value(joinedDate).notNull(); + /*if(this.fromApiJsonHelper.parameterExists(ClientApiConstants.datatables,element)){ + baseDataValidator.reset().parameter(ClientApiConstants.activeParamName).value(active) + .failWithCodeNoParameterAddedToErrorCode("should.not.be.used.with.datatables.parameter"); + }*/ } } else { baseDataValidator.reset().parameter(ClientApiConstants.activeParamName).value(active).trueOrFalseRequired(false); @@ -193,8 +205,13 @@ public final class ClientDataValidator { final Integer legalFormId = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(ClientApiConstants.legalFormIdParamName, element); baseDataValidator.reset().parameter(ClientApiConstants.legalFormIdParamName).value(legalFormId).ignoreIfNull().inMinMaxRange(1, 2); } - - List dataValidationErrorsForClientNonPerson = getDataValidationErrorsForCreateOnClientNonPerson(element.getAsJsonObject().get(ClientApiConstants.clientNonPersonDetailsParamName)); + + if(this.fromApiJsonHelper.parameterExists(ClientApiConstants.datatables, element)){ + final JsonArray datatables = this.fromApiJsonHelper.extractJsonArrayNamed(ClientApiConstants.datatables, element); + baseDataValidator.reset().parameter(ClientApiConstants.datatables).value(datatables).notNull().jsonArrayNotEmpty(); + } + + List dataValidationErrorsForClientNonPerson = getDataValidationErrorsForCreateOnClientNonPerson(element.getAsJsonObject().get(ClientApiConstants.clientNonPersonDetailsParamName)); dataValidationErrors.addAll(dataValidationErrorsForClientNonPerson); throwExceptionIfValidationWarningsExist(dataValidationErrors); @@ -236,8 +253,8 @@ public final class ClientDataValidator { element); baseDataValidator.reset().parameter(ClientApiConstants.mainBusinessLineIdParamName).value(mainBusinessLine).integerGreaterThanZero(); } - - return dataValidationErrors; + + return dataValidationErrors; } private void validateIndividualNamePartsCannotBeUsedWithFullname(final JsonElement element, final DataValidatorBuilder baseDataValidator) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java index bec536939..cab88f716 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java @@ -36,6 +36,10 @@ import org.apache.fineract.infrastructure.core.service.Page; import org.apache.fineract.infrastructure.core.service.PaginationHelper; import org.apache.fineract.infrastructure.core.service.RoutingDataSource; import org.apache.fineract.infrastructure.core.service.SearchParameters; +import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; +import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; +import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; +import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.organisation.office.data.OfficeData; import org.apache.fineract.organisation.office.service.OfficeReadPlatformService; @@ -81,6 +85,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService private final AddressReadPlatformService addressReadPlatformService; private final ConfigurationReadPlatformService configurationReadPlatformService; + private final EntityDatatableChecksReadService entityDatatableChecksReadService; @Autowired public ClientReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource, @@ -88,7 +93,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService final CodeValueReadPlatformService codeValueReadPlatformService, final SavingsProductReadPlatformService savingsProductReadPlatformService, final AddressReadPlatformService addressReadPlatformService, - final ConfigurationReadPlatformService configurationReadPlatformService) { + final ConfigurationReadPlatformService configurationReadPlatformService, + final EntityDatatableChecksReadService entityDatatableChecksReadService) { this.context = context; this.officeReadPlatformService = officeReadPlatformService; this.jdbcTemplate = new JdbcTemplate(dataSource); @@ -97,6 +103,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService this.savingsProductReadPlatformService = savingsProductReadPlatformService; this.addressReadPlatformService=addressReadPlatformService; this.configurationReadPlatformService=configurationReadPlatformService; + this.entityDatatableChecksReadService = entityDatatableChecksReadService; } @Override @@ -149,9 +156,12 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService final List clientLegalFormOptions = ClientEnumerations.legalForm(LegalForm.values()); + final List datatableTemplates = this.entityDatatableChecksReadService + .retrieveTemplates(StatusEnum.CREATE.getCode().longValue(), EntityTables.CLIENT.getName(), null); + return ClientData.template(defaultOfficeId, new LocalDate(), offices, staffOptions, null, genderOptions, savingsProductDatas, clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, - clientLegalFormOptions,address,isAddressEnabled); + clientLegalFormOptions,address,isAddressEnabled, datatableTemplates); } @Override @@ -782,7 +792,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService final Collection clientNonPersonMainBusinessLineOptions = null; final List clientLegalFormOptions = null; return ClientData.template(null, null, null, null, narrations, null, null, clientTypeOptions, clientClassificationOptions, - clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, clientLegalFormOptions,null,null); + clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, clientLegalFormOptions,null,null, null); } } \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java index 9a25264f1..d2fa74c10 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java @@ -18,12 +18,7 @@ */ package org.apache.fineract.portfolio.client.service; - -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; +import java.util.*; import javax.persistence.PersistenceException; @@ -44,6 +39,9 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; +import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; +import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; +import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.organisation.office.domain.Office; import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper; @@ -52,18 +50,8 @@ import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper; import org.apache.fineract.portfolio.address.service.AddressWritePlatformService; import org.apache.fineract.portfolio.client.api.ClientApiConstants; import org.apache.fineract.portfolio.client.data.ClientDataValidator; -import org.apache.fineract.portfolio.client.domain.AccountNumberGenerator; -import org.apache.fineract.portfolio.client.domain.Client; -import org.apache.fineract.portfolio.client.domain.ClientNonPerson; -import org.apache.fineract.portfolio.client.domain.ClientNonPersonRepositoryWrapper; -import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; -import org.apache.fineract.portfolio.client.domain.ClientStatus; -import org.apache.fineract.portfolio.client.domain.LegalForm; -import org.apache.fineract.portfolio.client.exception.ClientActiveForUpdateException; -import org.apache.fineract.portfolio.client.exception.ClientHasNoStaffException; -import org.apache.fineract.portfolio.client.exception.ClientMustBePendingToBeDeletedException; -import org.apache.fineract.portfolio.client.exception.InvalidClientSavingProductException; -import org.apache.fineract.portfolio.client.exception.InvalidClientStateTransitionException; +import org.apache.fineract.portfolio.client.domain.*; +import org.apache.fineract.portfolio.client.exception.*; import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY; import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS; import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService; @@ -121,7 +109,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP private final ConfigurationReadPlatformService configurationReadPlatformService; private final AddressWritePlatformService addressWritePlatformService; private final BusinessEventNotifierService businessEventNotifierService; - + private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService; @Autowired public ClientWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final ClientRepositoryWrapper clientRepository, final ClientNonPersonRepositoryWrapper clientNonPersonRepository, @@ -134,7 +122,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP final CommandProcessingService commandProcessingService, final ConfigurationDomainService configurationDomainService, final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository, final FromJsonHelper fromApiJsonHelper, final ConfigurationReadPlatformService configurationReadPlatformService, - final AddressWritePlatformService addressWritePlatformService, final BusinessEventNotifierService businessEventNotifierService) { + final AddressWritePlatformService addressWritePlatformService, final BusinessEventNotifierService businessEventNotifierService, + final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService) { this.context = context; this.clientRepository = clientRepository; this.clientNonPersonRepository = clientNonPersonRepository; @@ -156,6 +145,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP this.configurationReadPlatformService = configurationReadPlatformService; this.addressWritePlatformService = addressWritePlatformService; this.businessEventNotifierService = businessEventNotifierService; + this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService; } @Transactional @@ -314,6 +304,15 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP this.addressWritePlatformService.addNewClientAddress(newClient, command); } + if(command.parameterExists(ClientApiConstants.datatables)){ + this.entityDatatableChecksWritePlatformService.saveDatatables(StatusEnum.CREATE.getCode().longValue(), + EntityTables.CLIENT.getName(), newClient.getId(), null, + command.arrayOfParameterNamed(ClientApiConstants.datatables)); + } + + this.entityDatatableChecksWritePlatformService.runTheCheck(newClient.getId(), EntityTables.CLIENT.getName(), + StatusEnum.CREATE.getCode().longValue(), EntityTables.CLIENT.getForeignKeyColumnNameOnDatatable()); + return new CommandProcessingResultBuilder() // .withCommandId(command.commandId()) // .withOfficeId(clientOffice.getId()) // @@ -534,6 +533,9 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); final LocalDate activationDate = command.localDateValueOfParameterNamed("activationDate"); + entityDatatableChecksWritePlatformService.runTheCheck(clientId, EntityTables.CLIENT.getName(), + StatusEnum.ACTIVATE.getCode().longValue(), EntityTables.CLIENT.getForeignKeyColumnNameOnDatatable()); + final AppUser currentUser = this.context.authenticatedUser(); client.activate(currentUser, fmt, activationDate); CommandProcessingResult result = openSavingsAccount(client, fmt); @@ -668,6 +670,9 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP throw new InvalidClientStateTransitionException("close", "date.cannot.before.client.actvation.date", errorMessage, closureDate, client.getActivationLocalDate()); } + entityDatatableChecksWritePlatformService.runTheCheck(clientId,EntityTables.CLIENT.getName(), + StatusEnum.CLOSE.getCode().longValue(),EntityTables.CLIENT.getForeignKeyColumnNameOnDatatable()); + final List clientLoans = this.loanRepositoryWrapper.findLoanByClientId(clientId); for (final Loan loan : clientLoans) { final LoanStatusMapper loanStatus = new LoanStatusMapper(loan.status().getValue()); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java index 367cae541..0195e99cd 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java @@ -18,11 +18,7 @@ */ package org.apache.fineract.portfolio.group.api; -import java.util.Arrays; -import java.util.Collection; -import java.util.Date; -import java.util.HashSet; -import java.util.Set; +import java.util.*; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; @@ -54,6 +50,10 @@ import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer; import org.apache.fineract.infrastructure.core.service.Page; import org.apache.fineract.infrastructure.core.service.SearchParameters; +import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; +import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; +import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; +import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.accountdetails.data.AccountSummaryCollectionData; import org.apache.fineract.portfolio.accountdetails.service.AccountDetailsReadPlatformService; @@ -92,6 +92,7 @@ public class CentersApiResource { private final AccountDetailsReadPlatformService accountDetailsReadPlatformService; private final CalendarReadPlatformService calendarReadPlatformService; private final MeetingReadPlatformService meetingReadPlatformService; + private final EntityDatatableChecksReadService entityDatatableChecksReadService; @Autowired public CentersApiResource(final PlatformSecurityContext context, final CenterReadPlatformService centerReadPlatformService, @@ -101,7 +102,8 @@ public class CentersApiResource { final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService, final CollectionSheetReadPlatformService collectionSheetReadPlatformService, final FromJsonHelper fromJsonHelper, final AccountDetailsReadPlatformService accountDetailsReadPlatformService, - final CalendarReadPlatformService calendarReadPlatformService, final MeetingReadPlatformService meetingReadPlatformService) { + final CalendarReadPlatformService calendarReadPlatformService, final MeetingReadPlatformService meetingReadPlatformService, + final EntityDatatableChecksReadService entityDatatableChecksReadService) { this.context = context; this.centerReadPlatformService = centerReadPlatformService; this.centerApiJsonSerializer = centerApiJsonSerializer; @@ -114,6 +116,7 @@ public class CentersApiResource { this.accountDetailsReadPlatformService = accountDetailsReadPlatformService; this.calendarReadPlatformService = calendarReadPlatformService; this.meetingReadPlatformService = meetingReadPlatformService; + this.entityDatatableChecksReadService = entityDatatableChecksReadService; } @GET @@ -134,6 +137,9 @@ public class CentersApiResource { } final CenterData template = this.centerReadPlatformService.retrieveTemplate(officeId, staffInSelectedOfficeOnly); + final List datatableTemplates = this.entityDatatableChecksReadService + .retrieveTemplates(StatusEnum.CREATE.getCode().longValue(), EntityTables.GROUP.getName(), null); + template.setDatatables(datatableTemplates); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); return this.centerApiJsonSerializer.serialize(settings, template, GroupingTypesApiConstants.CENTER_RESPONSE_DATA_PARAMETERS); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupingTypesApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupingTypesApiConstants.java index bf1d6d097..bc3ebd0d6 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupingTypesApiConstants.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupingTypesApiConstants.java @@ -87,13 +87,15 @@ public class GroupingTypesApiConstants { // staff centres parameters public static final String meetingFallCenters = "meetingFallCenters"; + public static final String datatables = "datatables"; + public static final Set CENTER_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName, dateFormatParamName, idParamName, nameParamName, externalIdParamName, officeIdParamName, staffIdParamName, activeParamName, - activationDateParamName, groupMembersParamName, submittedOnDateParamName)); + activationDateParamName, groupMembersParamName, submittedOnDateParamName, datatables)); public static final Set GROUP_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName, dateFormatParamName, idParamName, nameParamName, externalIdParamName, centerIdParamName, officeIdParamName, staffIdParamName, activeParamName, - activationDateParamName, clientMembersParamName, collectionMeetingCalendar, submittedOnDateParamName)); + activationDateParamName, clientMembersParamName, collectionMeetingCalendar, submittedOnDateParamName, datatables)); public static final Set GROUP_ROLES_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(roleParamName, clientIdParamName)); @@ -106,16 +108,16 @@ public class GroupingTypesApiConstants { public static final Set CENTER_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName, nameParamName, externalIdParamName, officeIdParamName, officeNameParamName, staffIdParamName, staffNameParamName, hierarchyParamName, officeOptionsParamName, staffOptionsParamName, statusParamName, activeParamName, activationDateParamName, timeLine, - groupMembersParamName, collectionMeetingCalendar, closureReasons)); + groupMembersParamName, collectionMeetingCalendar, closureReasons, datatables)); public static final Set CENTER_GROUP_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName, nameParamName, externalIdParamName, officeIdParamName, officeNameParamName, staffIdParamName, staffNameParamName, hierarchyParamName, - officeOptionsParamName, staffOptionsParamName, clientOptionsParamName)); + officeOptionsParamName, staffOptionsParamName, clientOptionsParamName, datatables)); public static final Set GROUP_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName, nameParamName, externalIdParamName, officeIdParamName, officeNameParamName, "parentId", "parentName", staffIdParamName, staffNameParamName, hierarchyParamName, officeOptionsParamName, statusParamName, activeParamName, activationDateParamName, staffOptionsParamName, - clientOptionsParamName, timeLine)); + clientOptionsParamName, timeLine, datatables)); public static final Set ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName, dateFormatParamName, activationDateParamName)); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java index 033a8dba1..96dc132a9 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java @@ -53,6 +53,10 @@ import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer; import org.apache.fineract.infrastructure.core.service.Page; import org.apache.fineract.infrastructure.core.service.SearchParameters; +import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; +import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; +import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; +import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.accountdetails.data.AccountSummaryCollectionData; import org.apache.fineract.portfolio.accountdetails.service.AccountDetailsReadPlatformService; @@ -99,6 +103,7 @@ public class GroupsApiResource { private final AccountDetailsReadPlatformService accountDetailsReadPlatformService; private final CalendarReadPlatformService calendarReadPlatformService; private final MeetingReadPlatformService meetingReadPlatformService; + private final EntityDatatableChecksReadService entityDatatableChecksReadService; @Autowired public GroupsApiResource(final PlatformSecurityContext context, final GroupReadPlatformService groupReadPlatformService, @@ -111,7 +116,8 @@ public class GroupsApiResource { final CollectionSheetReadPlatformService collectionSheetReadPlatformService, final FromJsonHelper fromJsonHelper, final GroupRolesReadPlatformService groupRolesReadPlatformService, final AccountDetailsReadPlatformService accountDetailsReadPlatformService, - final CalendarReadPlatformService calendarReadPlatformService, final MeetingReadPlatformService meetingReadPlatformService) { + final CalendarReadPlatformService calendarReadPlatformService, final MeetingReadPlatformService meetingReadPlatformService, + final EntityDatatableChecksReadService entityDatatableChecksReadService) { this.context = context; this.groupReadPlatformService = groupReadPlatformService; @@ -128,6 +134,7 @@ public class GroupsApiResource { this.accountDetailsReadPlatformService = accountDetailsReadPlatformService; this.calendarReadPlatformService = calendarReadPlatformService; this.meetingReadPlatformService = meetingReadPlatformService; + this.entityDatatableChecksReadService = entityDatatableChecksReadService; } @GET @@ -148,8 +155,11 @@ public class GroupsApiResource { GroupingTypesApiConstants.GROUP_RESPONSE_DATA_PARAMETERS); } + final List datatableTemplates = this.entityDatatableChecksReadService + .retrieveTemplates(StatusEnum.CREATE.getCode().longValue(), EntityTables.GROUP.getName(), null); if (centerId != null) { final GroupGeneralData centerGroupTemplate = this.centerReadPlatformService.retrieveCenterGroupTemplate(centerId); + centerGroupTemplate.setDatatables(datatableTemplates); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); return this.groupGeneralApiJsonSerializer.serialize(settings, centerGroupTemplate, GroupingTypesApiConstants.CENTER_GROUP_RESPONSE_DATA_PARAMETERS); @@ -157,6 +167,8 @@ public class GroupsApiResource { final GroupGeneralData groupTemplate = this.groupReadPlatformService.retrieveTemplate(officeId, isCenterGroup, staffInSelectedOfficeOnly); + groupTemplate.setDatatables(datatableTemplates); + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); return this.groupGeneralApiJsonSerializer.serialize(settings, groupTemplate, GroupingTypesApiConstants.GROUP_RESPONSE_DATA_PARAMETERS); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterData.java index b05267df9..2d2828d60 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterData.java @@ -20,9 +20,11 @@ package org.apache.fineract.portfolio.group.data; import java.math.BigDecimal; import java.util.Collection; +import java.util.List; import org.apache.fineract.infrastructure.codes.data.CodeValueData; import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; import org.apache.fineract.organisation.office.data.OfficeData; import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.portfolio.calendar.data.CalendarData; @@ -63,6 +65,8 @@ public class CenterData { private final BigDecimal totaldue; private final BigDecimal installmentDue; + private List datatables = null; + public static CenterData template(final Long officeId, final String accountNo, final LocalDate activationDate, final Collection officeOptions, final Collection staffOptions, final Collection groupMembersOptions, final BigDecimal totalCollected, final BigDecimal totalOverdue, @@ -204,4 +208,8 @@ public class CenterData { public String getStaffName() { return this.staffName; } + + public void setDatatables(final List datatables) { + this.datatables = datatables; + } } \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupGeneralData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupGeneralData.java index 942e655d2..d6c225964 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupGeneralData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupGeneralData.java @@ -19,9 +19,11 @@ package org.apache.fineract.portfolio.group.data; import java.util.Collection; +import java.util.List; import org.apache.fineract.infrastructure.codes.data.CodeValueData; import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; import org.apache.fineract.organisation.office.data.OfficeData; import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.portfolio.calendar.data.CalendarData; @@ -70,6 +72,8 @@ public class GroupGeneralData { private final Collection closureReasons; private final GroupTimelineData timeline; + private List datatables = null; + public static GroupGeneralData lookup(final Long groupId, final String accountNo, final String groupName) { final Collection clientMembers = null; final Collection groupRoles = null; @@ -256,4 +260,8 @@ public class GroupGeneralData { public Collection clientMembers() { return this.clientMembers; } + + public void setDatatables(final List datatables) { + this.datatables = datatables; + } } \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/serialization/GroupingTypesDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/serialization/GroupingTypesDataValidator.java index bf5362dff..b30de36a9 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/serialization/GroupingTypesDataValidator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/serialization/GroupingTypesDataValidator.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import com.google.gson.JsonArray; import org.apache.commons.lang.StringUtils; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.ApiParameterError; @@ -116,6 +117,11 @@ public final class GroupingTypesDataValidator { baseDataValidator.reset().parameter(GroupingTypesApiConstants.submittedOnDateParamName).value(submittedOnDate).notNull(); } + if(this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.datatables, element)){ + final JsonArray datatables = this.fromApiJsonHelper.extractJsonArrayNamed(GroupingTypesApiConstants.datatables, element); + baseDataValidator.reset().parameter(GroupingTypesApiConstants.datatables).value(datatables).notNull().jsonArrayNotEmpty(); + } + throwExceptionIfValidationWarningsExist(dataValidationErrors); } @@ -180,6 +186,11 @@ public final class GroupingTypesDataValidator { baseDataValidator.reset().parameter(GroupingTypesApiConstants.submittedOnDateParamName).value(submittedOnDate).notNull(); } + if(this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.datatables, element)){ + final JsonArray datatables = this.fromApiJsonHelper.extractJsonArrayNamed(GroupingTypesApiConstants.datatables, element); + baseDataValidator.reset().parameter(GroupingTypesApiConstants.datatables).value(datatables).notNull().jsonArrayNotEmpty(); + } + throwExceptionIfValidationWarningsExist(dataValidationErrors); } @@ -240,6 +251,11 @@ public final class GroupingTypesDataValidator { baseDataValidator.reset().parameter(GroupingTypesApiConstants.submittedOnDateParamName).value(submittedOnDate).notNull(); } + if(this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.datatables, element)){ + final JsonArray datatables = this.fromApiJsonHelper.extractJsonArrayNamed(GroupingTypesApiConstants.datatables, element); + baseDataValidator.reset().parameter(GroupingTypesApiConstants.datatables).value(datatables).notNull().jsonArrayNotEmpty(); + } + throwExceptionIfValidationWarningsExist(dataValidationErrors); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java index 0cfc7f955..19b4a41e5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java @@ -18,13 +18,7 @@ */ package org.apache.fineract.portfolio.group.service; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import javax.persistence.PersistenceException; @@ -43,33 +37,24 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException; import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; +import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; +import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; +import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.organisation.office.domain.Office; import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper; import org.apache.fineract.organisation.office.exception.InvalidOfficeException; import org.apache.fineract.organisation.staff.domain.Staff; import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper; +import org.apache.fineract.portfolio.calendar.domain.*; import org.apache.fineract.portfolio.calendar.domain.Calendar; -import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType; -import org.apache.fineract.portfolio.calendar.domain.CalendarInstance; -import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository; -import org.apache.fineract.portfolio.calendar.domain.CalendarType; import org.apache.fineract.portfolio.client.domain.AccountNumberGenerator; import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; import org.apache.fineract.portfolio.client.service.LoanStatusMapper; import org.apache.fineract.portfolio.group.api.GroupingTypesApiConstants; -import org.apache.fineract.portfolio.group.domain.Group; -import org.apache.fineract.portfolio.group.domain.GroupLevel; -import org.apache.fineract.portfolio.group.domain.GroupLevelRepository; -import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper; -import org.apache.fineract.portfolio.group.domain.GroupTypes; -import org.apache.fineract.portfolio.group.exception.GroupAccountExistsException; -import org.apache.fineract.portfolio.group.exception.GroupHasNoStaffException; -import org.apache.fineract.portfolio.group.exception.GroupMemberCountNotInPermissibleRangeException; -import org.apache.fineract.portfolio.group.exception.GroupMustBePendingToBeDeletedException; -import org.apache.fineract.portfolio.group.exception.InvalidGroupLevelException; -import org.apache.fineract.portfolio.group.exception.InvalidGroupStateTransitionException; +import org.apache.fineract.portfolio.group.domain.*; +import org.apache.fineract.portfolio.group.exception.*; import org.apache.fineract.portfolio.group.serialization.GroupingTypesDataValidator; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper; @@ -109,6 +94,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group private final SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper; private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository; private final AccountNumberGenerator accountNumberGenerator; + private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService; @Autowired public GroupingTypesWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, @@ -119,7 +105,8 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group final CodeValueRepositoryWrapper codeValueRepository, final CommandProcessingService commandProcessingService, final CalendarInstanceRepository calendarInstanceRepository, final ConfigurationDomainService configurationDomainService, final LoanRepositoryWrapper loanRepositoryWrapper, - final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository, final AccountNumberGenerator accountNumberGenerator) { + final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository, final AccountNumberGenerator accountNumberGenerator, + final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService) { this.context = context; this.groupRepository = groupRepository; this.clientRepositoryWrapper = clientRepositoryWrapper; @@ -136,6 +123,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group this.loanRepositoryWrapper = loanRepositoryWrapper; this.accountNumberFormatRepository = accountNumberFormatRepository; this.accountNumberGenerator = accountNumberGenerator; + this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService; } private CommandProcessingResult createGroupingType(final JsonCommand command, final GroupTypes groupingType, final Long centerId) { @@ -219,6 +207,16 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group this.groupRepository.saveAndFlush(newGroup); newGroup.captureStaffHistoryDuringCenterCreation(staff, activationDate); + + if(command.parameterExists(GroupingTypesApiConstants.datatables)){ + this.entityDatatableChecksWritePlatformService.saveDatatables(StatusEnum.CREATE.getCode().longValue(), + EntityTables.GROUP.getName(), newGroup.getId(), null, + command.arrayOfParameterNamed(GroupingTypesApiConstants.datatables)); + } + + this.entityDatatableChecksWritePlatformService.runTheCheck(newGroup.getId(), EntityTables.GROUP.getName(), + StatusEnum.CREATE.getCode().longValue(), EntityTables.GROUP.getForeignKeyColumnNameOnDatatable()); + return new CommandProcessingResultBuilder() // .withCommandId(command.commandId()) // .withOfficeId(groupOffice.getId()) // @@ -296,6 +294,10 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group final LocalDate activationDate = command.localDateValueOfParameterNamed("activationDate"); validateOfficeOpeningDateisAfterGroupOrCenterOpeningDate(group.getOffice(), group.getGroupLevel(), activationDate); + + entityDatatableChecksWritePlatformService.runTheCheck(groupId, EntityTables.GROUP.getName(), + StatusEnum.ACTIVATE.getCode().longValue(), EntityTables.GROUP.getForeignKeyColumnNameOnDatatable()); + group.activate(currentUser, activationDate); this.groupRepository.saveAndFlush(group); @@ -585,6 +587,9 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group validateLoansAndSavingsForGroupOrCenterClose(group, closureDate); + entityDatatableChecksWritePlatformService.runTheCheck(groupId, EntityTables.GROUP.getName(), + StatusEnum.CLOSE.getCode().longValue(),EntityTables.GROUP.getForeignKeyColumnNameOnDatatable()); + group.close(currentUser, closureReason, closureDate); this.groupRepository.saveAndFlush(group); @@ -657,6 +662,10 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group validateLoansAndSavingsForGroupOrCenterClose(center, closureDate); + entityDatatableChecksWritePlatformService.runTheCheck(centerId, EntityTables.GROUP.getName(), + StatusEnum.ACTIVATE.getCode().longValue(), EntityTables.GROUP.getForeignKeyColumnNameOnDatatable()); + + center.close(currentUser, closureReason, closureDate); this.groupRepository.saveAndFlush(center); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java index d31232451..6e5376a79 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java @@ -123,4 +123,5 @@ public interface LoanApiConstants { public static final String loanIdToClose = "loanIdToClose"; public static final String topupAmount = "topupAmount"; + public static final String datatables = "datatables"; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java index c236e37e7..bded4157b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java @@ -20,12 +20,7 @@ package org.apache.fineract.portfolio.loanaccount.api; import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.interestType; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; @@ -58,6 +53,10 @@ import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSer import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.core.service.Page; import org.apache.fineract.infrastructure.core.service.SearchParameters; +import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; +import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; +import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; +import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.staff.data.StaffData; @@ -139,7 +138,8 @@ public class LoansApiResource { "loanOfficerOptions", "loanPurposeOptions", "loanCollateralOptions", "chargeTemplate", "calendarOptions", "syncDisbursementWithMeeting", "loanCounter", "loanProductCounter", "notes", "accountLinkingOptions", "linkedAccount", "interestRateDifferential", "isFloatingInterestRate", "interestRatesPeriods", LoanApiConstants.canUseForTopup, - LoanApiConstants.isTopup, LoanApiConstants.loanIdToClose, LoanApiConstants.topupAmount, LoanApiConstants.clientActiveLoanOptions)); + LoanApiConstants.isTopup, LoanApiConstants.loanIdToClose, LoanApiConstants.topupAmount, LoanApiConstants.clientActiveLoanOptions, + LoanApiConstants.datatables)); private final Set LOAN_APPROVAL_DATA_PARAMETERS = new HashSet<>(Arrays.asList("approvalDate", "approvalAmount")); private final String resourceNameForPermissions = "LOAN"; @@ -168,6 +168,7 @@ public class LoansApiResource { private final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService; private final LoanScheduleHistoryReadPlatformService loanScheduleHistoryReadPlatformService; private final AccountDetailsReadPlatformService accountDetailsReadPlatformService; + private final EntityDatatableChecksReadService entityDatatableChecksReadService; @Autowired public LoansApiResource(final PlatformSecurityContext context, final LoanReadPlatformService loanReadPlatformService, @@ -187,7 +188,8 @@ public class LoansApiResource { final PortfolioAccountReadPlatformService portfolioAccountReadPlatformServiceImpl, final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService, final LoanScheduleHistoryReadPlatformService loanScheduleHistoryReadPlatformService, - final AccountDetailsReadPlatformService accountDetailsReadPlatformService) { + final AccountDetailsReadPlatformService accountDetailsReadPlatformService, + final EntityDatatableChecksReadService entityDatatableChecksReadService) { this.context = context; this.loanReadPlatformService = loanReadPlatformService; this.loanProductReadPlatformService = loanProductReadPlatformService; @@ -212,6 +214,7 @@ public class LoansApiResource { this.accountAssociationsReadPlatformService = accountAssociationsReadPlatformService; this.loanScheduleHistoryReadPlatformService = loanScheduleHistoryReadPlatformService; this.accountDetailsReadPlatformService = accountDetailsReadPlatformService; + this.entityDatatableChecksReadService = entityDatatableChecksReadService; } /* @@ -347,6 +350,10 @@ public class LoansApiResource { newLoanAccount = LoanAccountData.associationsAndTemplate(newLoanAccount, productOptions, allowedLoanOfficers, calendarOptions, accountLinkingOptions); } + final List datatableTemplates = this.entityDatatableChecksReadService + .retrieveTemplates(StatusEnum.CREATE.getCode().longValue(), EntityTables.LOAN.getName(), productId); + newLoanAccount.setDatatables(datatableTemplates); + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); return this.toApiJsonSerializer.serialize(settings, newLoanAccount, this.LOAN_DATA_PARAMETERS); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java index 5a250b315..5109c3e71 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java @@ -19,15 +19,13 @@ package org.apache.fineract.portfolio.loanaccount.data; import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import javax.persistence.Transient; import org.apache.fineract.infrastructure.codes.data.CodeValueData; import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.portfolio.account.data.PortfolioAccountData; @@ -214,6 +212,8 @@ public class LoanAccountData { private final Integer minimumGap; private final Integer maximumGap; + private List datatables = null; + /** * Used to produce a {@link LoanAccountData} with only collateral options * for now. @@ -1618,4 +1618,8 @@ public class LoanAccountData { public BigDecimal getInterestRateDifferential() { return this.interestRateDifferential; } + + public void setDatatables(final List datatables) { + this.datatables = datatables; + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java index 8f871b0ed..523207d80 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java @@ -37,6 +37,7 @@ import org.apache.fineract.infrastructure.core.exception.UnsupportedParameterExc import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.portfolio.accountdetails.domain.AccountType; import org.apache.fineract.portfolio.calendar.service.CalendarUtils; +import org.apache.fineract.portfolio.client.api.ClientApiConstants; import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge; @@ -92,7 +93,7 @@ public final class LoanApplicationCommandFromApiJsonHelper { LoanApiConstants.linkAccountIdParameterName, LoanApiConstants.disbursementDataParameterName, LoanApiConstants.emiAmountParameterName, LoanApiConstants.maxOutstandingBalanceParameterName, LoanProductConstants.graceOnArrearsAgeingParameterName, LoanApiConstants.createStandingInstructionAtDisbursementParameterName, - LoanApiConstants.isTopup, LoanApiConstants.loanIdToClose)); + LoanApiConstants.isTopup, LoanApiConstants.loanIdToClose, LoanApiConstants.datatables)); private final FromJsonHelper fromApiJsonHelper; private final CalculateLoanScheduleQueryFromApiJsonHelper apiJsonHelper; @@ -482,6 +483,11 @@ public final class LoanApplicationCommandFromApiJsonHelper { } } } + if(this.fromApiJsonHelper.parameterExists(LoanApiConstants.datatables, element)){ + final JsonArray datatables = this.fromApiJsonHelper.extractJsonArrayNamed(LoanApiConstants.datatables, element); + baseDataValidator.reset().parameter(LoanApiConstants.datatables).value(datatables).notNull().jsonArrayNotEmpty(); + } + validateLoanMultiDisbursementdate(element, baseDataValidator, expectedDisbursementDate, principal); validatePartialPeriodSupport(interestCalculationPeriodType, baseDataValidator, element, loanProduct); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java index 221273f38..fe17b5c47 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java @@ -19,14 +19,8 @@ package org.apache.fineract.portfolio.loanaccount.service; import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; -import javax.persistence.EntityExistsException; import javax.persistence.PersistenceException; import org.apache.commons.lang.StringUtils; @@ -48,12 +42,11 @@ import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRu import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; +import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; +import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; +import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService; import org.apache.fineract.infrastructure.entityaccess.FineractEntityAccessConstants; -import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityAccessType; -import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityRelation; -import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityRelationRepository; -import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityToEntityMapping; -import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityToEntityMappingRepository; +import org.apache.fineract.infrastructure.entityaccess.domain.*; import org.apache.fineract.infrastructure.entityaccess.exception.NotOfficeSpecificProductException; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.organisation.staff.domain.Staff; @@ -61,13 +54,8 @@ import org.apache.fineract.portfolio.account.domain.AccountAssociationType; import org.apache.fineract.portfolio.account.domain.AccountAssociations; import org.apache.fineract.portfolio.account.domain.AccountAssociationsRepository; import org.apache.fineract.portfolio.accountdetails.domain.AccountType; +import org.apache.fineract.portfolio.calendar.domain.*; import org.apache.fineract.portfolio.calendar.domain.Calendar; -import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType; -import org.apache.fineract.portfolio.calendar.domain.CalendarFrequencyType; -import org.apache.fineract.portfolio.calendar.domain.CalendarInstance; -import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository; -import org.apache.fineract.portfolio.calendar.domain.CalendarRepository; -import org.apache.fineract.portfolio.calendar.domain.CalendarType; import org.apache.fineract.portfolio.calendar.exception.CalendarNotFoundException; import org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformService; import org.apache.fineract.portfolio.charge.domain.Charge; @@ -88,18 +76,7 @@ import org.apache.fineract.portfolio.group.exception.GroupNotActiveException; import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants; import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData; import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO; -import org.apache.fineract.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine; -import org.apache.fineract.portfolio.loanaccount.domain.Loan; -import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge; -import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails; -import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine; -import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; -import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository; -import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory; -import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper; -import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus; -import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper; -import org.apache.fineract.portfolio.loanaccount.domain.LoanTopupDetails; +import org.apache.fineract.portfolio.loanaccount.domain.*; import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationDateException; import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeDeleted; import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified; @@ -111,11 +88,7 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanSchedu import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationCommandFromApiJsonHelper; import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationTransitionApiJsonValidator; import org.apache.fineract.portfolio.loanproduct.LoanProductConstants; -import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; -import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail; -import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository; -import org.apache.fineract.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy; -import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType; +import org.apache.fineract.portfolio.loanproduct.domain.*; import org.apache.fineract.portfolio.loanproduct.exception.LinkedAccountRequiredException; import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException; import org.apache.fineract.portfolio.loanproduct.serialization.LoanProductDataValidator; @@ -170,6 +143,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa private final LoanScheduleAssembler loanScheduleAssembler; private final LoanUtilService loanUtilService; private final CalendarReadPlatformService calendarReadPlatformService; + private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService; private final GlobalConfigurationRepositoryWrapper globalConfigurationRepository; private final FineractEntityToEntityMappingRepository repository; private final FineractEntityRelationRepository fineractEntityRelationRepository; @@ -194,7 +168,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa final BusinessEventNotifierService businessEventNotifierService, final ConfigurationDomainService configurationDomainService, final LoanScheduleAssembler loanScheduleAssembler, final LoanUtilService loanUtilService, final CalendarReadPlatformService calendarReadPlatformService, final GlobalConfigurationRepositoryWrapper globalConfigurationRepository, - final FineractEntityToEntityMappingRepository repository, final FineractEntityRelationRepository fineractEntityRelationRepository) { + final FineractEntityToEntityMappingRepository repository, final FineractEntityRelationRepository fineractEntityRelationRepository, + final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService) { this.context = context; this.fromJsonHelper = fromJsonHelper; this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator; @@ -225,6 +200,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa this.loanScheduleAssembler = loanScheduleAssembler; this.loanUtilService = loanUtilService; this.calendarReadPlatformService = calendarReadPlatformService; + this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService; this.globalConfigurationRepository = globalConfigurationRepository; this.repository = repository; this.fineractEntityRelationRepository = fineractEntityRelationRepository; @@ -408,6 +384,17 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa this.accountAssociationsRepository.save(accountAssociations); } + if(command.parameterExists(LoanApiConstants.datatables)){ + this.entityDatatableChecksWritePlatformService.saveDatatables(StatusEnum.CREATE.getCode().longValue(), + EntityTables.LOAN.getName(), newLoanApplication.getId(), newLoanApplication.productId(), + command.arrayOfParameterNamed(LoanApiConstants.datatables)); + } + + this.entityDatatableChecksWritePlatformService.runTheCheckForProduct(newLoanApplication.getId(), + EntityTables.LOAN.getName(), StatusEnum.CREATE.getCode().longValue(), + EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), newLoanApplication.productId()); + + return new CommandProcessingResultBuilder() // .withCommandId(command.commandId()) // .withEntityId(newLoanApplication.getId()) // @@ -1107,6 +1094,9 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa final Map changes = loan.loanApplicationApproval(currentUser, command, disbursementDataArray, defaultLoanLifecycleStateMachine()); + entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(), + StatusEnum.APPROVE.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId()); + if (!changes.isEmpty()) { // If loan approved amount less than loan demanded amount, then need @@ -1221,8 +1211,12 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa this.loanApplicationTransitionApiJsonValidator.validateRejection(command.json()); final Loan loan = retrieveLoanBy(loanId); + checkClientOrGroupActive(loan); + entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(), + StatusEnum.REJECTED.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(),loan.productId()); + final Map changes = loan.loanApplicationRejection(currentUser, command, defaultLoanLifecycleStateMachine()); if (!changes.isEmpty()) { this.loanRepositoryWrapper.save(loan); @@ -1256,6 +1250,9 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa final Loan loan = retrieveLoanBy(loanId); checkClientOrGroupActive(loan); + entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(), + StatusEnum.WITHDRAWN.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId()); + final Map changes = loan.loanApplicationWithdrawnByApplicant(currentUser, command, defaultLoanLifecycleStateMachine()); if (!changes.isEmpty()) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java index 8850bf460..95b4c94c1 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -19,17 +19,7 @@ package org.apache.fineract.portfolio.loanaccount.service; import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; +import java.util.*; import org.apache.commons.lang.StringUtils; import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService; @@ -46,6 +36,9 @@ import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavailableException; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.core.service.DateUtils; +import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; +import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; +import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService; import org.apache.fineract.infrastructure.jobs.annotation.CronTarget; import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException; import org.apache.fineract.infrastructure.jobs.service.JobName; @@ -63,44 +56,22 @@ import org.apache.fineract.organisation.workingdays.domain.WorkingDaysRepository import org.apache.fineract.portfolio.account.PortfolioAccountType; import org.apache.fineract.portfolio.account.data.AccountTransferDTO; import org.apache.fineract.portfolio.account.data.PortfolioAccountData; -import org.apache.fineract.portfolio.account.domain.AccountAssociationType; -import org.apache.fineract.portfolio.account.domain.AccountAssociations; -import org.apache.fineract.portfolio.account.domain.AccountAssociationsRepository; -import org.apache.fineract.portfolio.account.domain.AccountTransferDetailRepository; -import org.apache.fineract.portfolio.account.domain.AccountTransferDetails; -import org.apache.fineract.portfolio.account.domain.AccountTransferRecurrenceType; -import org.apache.fineract.portfolio.account.domain.AccountTransferRepository; -import org.apache.fineract.portfolio.account.domain.AccountTransferStandingInstruction; -import org.apache.fineract.portfolio.account.domain.AccountTransferTransaction; -import org.apache.fineract.portfolio.account.domain.AccountTransferType; -import org.apache.fineract.portfolio.account.domain.StandingInstructionPriority; -import org.apache.fineract.portfolio.account.domain.StandingInstructionStatus; -import org.apache.fineract.portfolio.account.domain.StandingInstructionType; +import org.apache.fineract.portfolio.account.domain.*; import org.apache.fineract.portfolio.account.service.AccountAssociationsReadPlatformService; import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService; import org.apache.fineract.portfolio.account.service.AccountTransfersWritePlatformService; import org.apache.fineract.portfolio.accountdetails.domain.AccountType; +import org.apache.fineract.portfolio.calendar.domain.*; import org.apache.fineract.portfolio.calendar.domain.Calendar; -import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType; -import org.apache.fineract.portfolio.calendar.domain.CalendarInstance; -import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository; -import org.apache.fineract.portfolio.calendar.domain.CalendarRepository; -import org.apache.fineract.portfolio.calendar.domain.CalendarType; import org.apache.fineract.portfolio.calendar.exception.CalendarParameterUpdateNotSupportedException; import org.apache.fineract.portfolio.charge.domain.Charge; import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode; import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper; -import org.apache.fineract.portfolio.charge.exception.ChargeCannotBeUpdatedException; -import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeAddedException; -import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeDeletedException; +import org.apache.fineract.portfolio.charge.exception.*; import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeDeletedException.LOAN_CHARGE_CANNOT_BE_DELETED_REASON; -import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBePayedException; import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBePayedException.LOAN_CHARGE_CANNOT_BE_PAYED_REASON; -import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeUpdatedException; import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeUpdatedException.LOAN_CHARGE_CANNOT_BE_UPDATED_REASON; -import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeWaivedException; import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeWaivedException.LOAN_CHARGE_CANNOT_BE_WAIVED_REASON; -import org.apache.fineract.portfolio.charge.exception.LoanChargeNotFoundException; import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.portfolio.client.exception.ClientNotActiveException; import org.apache.fineract.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand; @@ -115,44 +86,9 @@ import org.apache.fineract.portfolio.group.domain.Group; import org.apache.fineract.portfolio.group.exception.GroupNotActiveException; import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants; import org.apache.fineract.portfolio.loanaccount.command.LoanUpdateCommand; -import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO; -import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData; -import org.apache.fineract.portfolio.loanaccount.data.LoanChargePaidByData; -import org.apache.fineract.portfolio.loanaccount.data.LoanInstallmentChargeData; -import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO; -import org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail; -import org.apache.fineract.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine; -import org.apache.fineract.portfolio.loanaccount.domain.Loan; -import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService; -import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge; -import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeRepository; -import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails; -import org.apache.fineract.portfolio.loanaccount.domain.LoanEvent; -import org.apache.fineract.portfolio.loanaccount.domain.LoanInstallmentCharge; -import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails; -import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine; -import org.apache.fineract.portfolio.loanaccount.domain.LoanOverdueInstallmentCharge; -import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; -import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository; -import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory; -import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper; -import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus; -import org.apache.fineract.portfolio.loanaccount.domain.LoanSubStatus; -import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper; -import org.apache.fineract.portfolio.loanaccount.domain.LoanTrancheDisbursementCharge; -import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; -import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository; -import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType; -import org.apache.fineract.portfolio.loanaccount.exception.DateMismatchException; -import org.apache.fineract.portfolio.loanaccount.exception.ExceedingTrancheCountException; -import org.apache.fineract.portfolio.loanaccount.exception.InvalidPaidInAdvanceAmountException; -import org.apache.fineract.portfolio.loanaccount.exception.LoanDisbursalException; -import org.apache.fineract.portfolio.loanaccount.exception.LoanForeclosureException; -import org.apache.fineract.portfolio.loanaccount.exception.LoanMultiDisbursementException; -import org.apache.fineract.portfolio.loanaccount.exception.LoanOfficerAssignmentException; -import org.apache.fineract.portfolio.loanaccount.exception.LoanOfficerUnassignmentException; -import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionNotFoundException; -import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementDataRequiredException; +import org.apache.fineract.portfolio.loanaccount.data.*; +import org.apache.fineract.portfolio.loanaccount.domain.*; +import org.apache.fineract.portfolio.loanaccount.exception.*; import org.apache.fineract.portfolio.loanaccount.guarantor.service.GuarantorDomainService; import org.apache.fineract.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator; @@ -231,6 +167,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf private final GuarantorDomainService guarantorDomainService; private final LoanUtilService loanUtilService; private final LoanSummaryWrapper loanSummaryWrapper; + private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService; private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy; private final CodeValueRepositoryWrapper codeValueRepository; @@ -260,6 +197,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final AccountTransferDetailRepository accountTransferDetailRepository, final BusinessEventNotifierService businessEventNotifierService, final GuarantorDomainService guarantorDomainService, final LoanUtilService loanUtilService, final LoanSummaryWrapper loanSummaryWrapper, + final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService, final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy, final CodeValueRepositoryWrapper codeValueRepository, final LoanRepositoryWrapper loanRepositoryWrapper) { @@ -299,6 +237,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf this.loanUtilService = loanUtilService; this.loanSummaryWrapper = loanSummaryWrapper; this.transactionProcessingStrategy = transactionProcessingStrategy; + this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService; this.codeValueRepository = codeValueRepository; } @@ -318,7 +257,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final Loan loan = this.loanAssembler.assembleFrom(loanId); final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate"); - // validate ActualDisbursement Date Against Expected Disbursement Date LoanProduct loanProduct = loan.loanProduct(); if(loanProduct.syncExpectedWithDisbursementDate()){ @@ -329,6 +267,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final LocalDate nextPossibleRepaymentDate = loan.getNextPossibleRepaymentDateForRescheduling(); final Date rescheduledRepaymentDate = command.DateValueOfParameterNamed("adjustRepaymentDate"); + entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(), + StatusEnum.ACTIVATE.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId()); + // check for product mix validations checkForProductMixRestrictions(loan); @@ -1114,6 +1055,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf checkClientOrGroupActive(loan); this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.LOAN_WRITTEN_OFF, constructEntityMap(BUSINESS_ENTITY.LOAN, loan)); + entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(), + StatusEnum.WRITE_OFF.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId()); + removeLoanCycle(loan); final List existingTransactionIds = new ArrayList<>(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java index 883f9adb3..6efa89932 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java @@ -167,6 +167,8 @@ public class SavingsApiConstants { public static final String daysToInactiveParamName = "daysToInactive"; public static final String daysToDormancyParamName = "daysToDormancy"; public static final String daysToEscheatParamName = "daysToEscheat"; + + public static final String datatables = "datatables"; public static final Set SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName, @@ -220,7 +222,7 @@ public class SavingsApiConstants { // withdrawalFeeAmountParamName, withdrawalFeeTypeParamName, withdrawalFeeForTransfersParamName, feeAmountParamName, feeOnMonthDayParamName, chargesParamName, allowOverdraftParamName, overdraftLimitParamName, minRequiredBalanceParamName, enforceMinRequiredBalanceParamName, - nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName, withHoldTaxParamName)); + nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName, withHoldTaxParamName,datatables)); /** * These parameters will match the class level parameters of @@ -236,7 +238,7 @@ public class SavingsApiConstants { feeOnMonthDayParamName, "summary", "transactions", "productOptions", "interestCompoundingPeriodTypeOptions", "interestPostingPeriodTypeOptions", "interestCalculationTypeOptions", "interestCalculationDaysInYearTypeOptions", "lockinPeriodFrequencyTypeOptions", "withdrawalFeeTypeOptions", "withdrawalFee", "annualFee", onHoldFundsParamName, - nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName)); + nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName, datatables)); public static final Set SAVINGS_ACCOUNT_TRANSACTION_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName, dateFormatParamName, transactionDateParamName, transactionAmountParamName, paymentTypeIdParamName, diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java index fa6064dc4..d06bbe934 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java @@ -21,10 +21,12 @@ package org.apache.fineract.portfolio.savings.data; import java.math.BigDecimal; import java.util.Collection; import java.util.HashSet; +import java.util.List; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.portfolio.charge.data.ChargeData; @@ -100,6 +102,8 @@ public class SavingsAccountData { private final BigDecimal nominalAnnualInterestRateOverdraft; private final BigDecimal minOverdraftForInterestCalculation; + private List datatables = null; + public static SavingsAccountData instance(final Long id, final String accountNo, final EnumOptionData depositType, final String externalId, final Long groupId, final String groupName, final Long clientId, final String clientName, final Long productId, final String productName, final Long fieldOfficerId, final String fieldOfficerName, @@ -557,4 +561,8 @@ public class SavingsAccountData { public Collection charges() { return (this.charges == null) ? new HashSet() : this.charges; } + + public void setDatatables(final List datatables) { + this.datatables = datatables; + } } \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountDataValidator.java index 586ef252d..4cc6e8961 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountDataValidator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountDataValidator.java @@ -212,6 +212,11 @@ public class SavingsAccountDataValidator { baseDataValidator.reset().parameter(withHoldTaxParamName).value(withHoldTax).ignoreIfNull().validateForBooleanValue(); } + if(this.fromApiJsonHelper.parameterExists(SavingsApiConstants.datatables, element)){ + final JsonArray datatables = this.fromApiJsonHelper.extractJsonArrayNamed(SavingsApiConstants.datatables, element); + baseDataValidator.reset().parameter(SavingsApiConstants.datatables).value(datatables).notNull().jsonArrayNotEmpty(); + } + validateSavingsCharges(element, baseDataValidator); validateOverdraftParams(baseDataValidator, element); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java index 38099d113..c91281111 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java @@ -34,6 +34,10 @@ import org.apache.fineract.infrastructure.core.service.Page; import org.apache.fineract.infrastructure.core.service.PaginationHelper; import org.apache.fineract.infrastructure.core.service.RoutingDataSource; import org.apache.fineract.infrastructure.core.service.SearchParameters; +import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; +import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; +import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; +import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.monetary.domain.Money; @@ -102,12 +106,15 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead // pagination private final PaginationHelper paginationHelper = new PaginationHelper<>(); + private final EntityDatatableChecksReadService entityDatatableChecksReadService; + @Autowired public SavingsAccountReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource, final ClientReadPlatformService clientReadPlatformService, final GroupReadPlatformService groupReadPlatformService, final SavingsProductReadPlatformService savingProductReadPlatformService, final StaffReadPlatformService staffReadPlatformService, final SavingsDropdownReadPlatformService dropdownReadPlatformService, - final ChargeReadPlatformService chargeReadPlatformService) { + final ChargeReadPlatformService chargeReadPlatformService, + final EntityDatatableChecksReadService entityDatatableChecksReadService) { this.context = context; this.jdbcTemplate = new JdbcTemplate(dataSource); this.clientReadPlatformService = clientReadPlatformService; @@ -120,6 +127,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead this.savingAccountMapper = new SavingAccountMapper(); // this.annualFeeMapper = new SavingsAccountAnnualFeeMapper(); this.chargeReadPlatformService = chargeReadPlatformService; + this.entityDatatableChecksReadService = entityDatatableChecksReadService; } @Override @@ -687,6 +695,10 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead charges, chargeOptions); } + final List datatableTemplates = this.entityDatatableChecksReadService + .retrieveTemplates(StatusEnum.CREATE.getCode().longValue(), EntityTables.SAVING.getName(), productId); + template.setDatatables(datatableTemplates); + return template; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java index 5d882c45d..2064f57ee 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java @@ -18,25 +18,11 @@ */ package org.apache.fineract.portfolio.savings.service; -import static org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_CHARGE_RESOURCE_NAME; -import static org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME; -import static org.apache.fineract.portfolio.savings.SavingsApiConstants.amountParamName; -import static org.apache.fineract.portfolio.savings.SavingsApiConstants.chargeIdParamName; -import static org.apache.fineract.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName; -import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withHoldTaxParamName; -import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawBalanceParamName; +import static org.apache.fineract.portfolio.savings.SavingsApiConstants.*; import java.math.BigDecimal; import java.math.MathContext; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; +import java.util.*; import org.apache.commons.lang.StringUtils; import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService; @@ -49,13 +35,12 @@ import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavailableException; import org.apache.fineract.infrastructure.core.service.DateUtils; +import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; +import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; +import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.organisation.holiday.domain.HolidayRepositoryWrapper; -import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; -import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; -import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; -import org.apache.fineract.organisation.monetary.domain.Money; -import org.apache.fineract.organisation.monetary.domain.MoneyHelper; +import org.apache.fineract.organisation.monetary.domain.*; import org.apache.fineract.organisation.office.domain.Office; import org.apache.fineract.organisation.staff.domain.Staff; import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper; @@ -87,25 +72,9 @@ import org.apache.fineract.portfolio.savings.data.SavingsAccountChargeDataValida import org.apache.fineract.portfolio.savings.data.SavingsAccountDataValidator; import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionDTO; import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionDataValidator; -import org.apache.fineract.portfolio.savings.domain.DepositAccountOnHoldTransaction; -import org.apache.fineract.portfolio.savings.domain.DepositAccountOnHoldTransactionRepository; -import org.apache.fineract.portfolio.savings.domain.SavingsAccount; -import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler; -import org.apache.fineract.portfolio.savings.domain.SavingsAccountCharge; -import org.apache.fineract.portfolio.savings.domain.SavingsAccountChargeRepositoryWrapper; -import org.apache.fineract.portfolio.savings.domain.SavingsAccountDomainService; -import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrapper; -import org.apache.fineract.portfolio.savings.domain.SavingsAccountStatusType; -import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction; -import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionRepository; -import org.apache.fineract.portfolio.savings.exception.PostInterestAsOnDateException; +import org.apache.fineract.portfolio.savings.domain.*; +import org.apache.fineract.portfolio.savings.exception.*; import org.apache.fineract.portfolio.savings.exception.PostInterestAsOnDateException.PostInterestAsOnException_TYPE; -import org.apache.fineract.portfolio.savings.exception.PostInterestClosingDateException; -import org.apache.fineract.portfolio.savings.exception.SavingsAccountClosingNotAllowedException; -import org.apache.fineract.portfolio.savings.exception.SavingsAccountTransactionNotFoundException; -import org.apache.fineract.portfolio.savings.exception.SavingsOfficerAssignmentException; -import org.apache.fineract.portfolio.savings.exception.SavingsOfficerUnassignmentException; -import org.apache.fineract.portfolio.savings.exception.TransactionUpdateNotAllowedException; import org.apache.fineract.useradministration.domain.AppUser; import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper; import org.joda.time.LocalDate; @@ -140,6 +109,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi private final WorkingDaysRepositoryWrapper workingDaysRepository; private final ConfigurationDomainService configurationDomainService; private final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository; + private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService; private final AppUserRepositoryWrapper appuserRepository; private final StandingInstructionRepository standingInstructionRepository; private final BusinessEventNotifierService businessEventNotifierService; @@ -162,6 +132,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi final SavingsAccountDataValidator fromApiJsonDeserializer, final StaffRepositoryWrapper staffRepository, final ConfigurationDomainService configurationDomainService, final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository, + final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService, final AppUserRepositoryWrapper appuserRepository, final StandingInstructionRepository standingInstructionRepository, final BusinessEventNotifierService businessEventNotifierService) { @@ -186,6 +157,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi this.staffRepository = staffRepository; this.configurationDomainService = configurationDomainService; this.depositAccountOnHoldTransactionRepository = depositAccountOnHoldTransactionRepository; + this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService; this.appuserRepository = appuserRepository; this.standingInstructionRepository = standingInstructionRepository; this.businessEventNotifierService = businessEventNotifierService; @@ -205,6 +177,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi final Set existingReversedTransactionIds = new HashSet<>(); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); final Map changes = account.activate(user, command, DateUtils.getLocalDateOfTenant()); + + entityDatatableChecksWritePlatformService.runTheCheckForProduct(savingsId, EntityTables.SAVING.getName(), + StatusEnum.ACTIVATE.getCode().longValue(),EntityTables.SAVING.getForeignKeyColumnNameOnDatatable(), + account.productId()); + if (!changes.isEmpty()) { final Locale locale = command.extractLocale(); final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); @@ -643,8 +620,10 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi + " is not allowed, since it is linked with one of the active accounts"; throw new SavingsAccountClosingNotAllowedException("linked", defaultUserMessage, savingsId); } - - + + entityDatatableChecksWritePlatformService.runTheCheckForProduct(savingsId, EntityTables.SAVING.getName(), + StatusEnum.CLOSE.getCode().longValue(),EntityTables.SAVING.getForeignKeyColumnNameOnDatatable(), + account.productId()); final boolean isWithdrawBalance = command.booleanPrimitiveValueOfParameterNamed(withdrawBalanceParamName); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java index 35b94f5df..45056ca2a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java @@ -20,13 +20,7 @@ package org.apache.fineract.portfolio.savings.service; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import javax.persistence.PersistenceException; @@ -46,6 +40,9 @@ import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; import org.apache.fineract.infrastructure.core.service.DateUtils; +import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; +import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; +import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.organisation.monetary.domain.Money; import org.apache.fineract.organisation.staff.domain.Staff; @@ -67,14 +64,7 @@ import org.apache.fineract.portfolio.note.domain.NoteRepository; import org.apache.fineract.portfolio.savings.SavingsApiConstants; import org.apache.fineract.portfolio.savings.data.SavingsAccountDataDTO; import org.apache.fineract.portfolio.savings.data.SavingsAccountDataValidator; -import org.apache.fineract.portfolio.savings.domain.SavingsAccount; -import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler; -import org.apache.fineract.portfolio.savings.domain.SavingsAccountCharge; -import org.apache.fineract.portfolio.savings.domain.SavingsAccountChargeAssembler; -import org.apache.fineract.portfolio.savings.domain.SavingsAccountDomainService; -import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrapper; -import org.apache.fineract.portfolio.savings.domain.SavingsProduct; -import org.apache.fineract.portfolio.savings.domain.SavingsProductRepository; +import org.apache.fineract.portfolio.savings.domain.*; import org.apache.fineract.portfolio.savings.exception.SavingsProductNotFoundException; import org.apache.fineract.useradministration.domain.AppUser; import org.slf4j.Logger; @@ -106,7 +96,8 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl private final SavingsAccountWritePlatformService savingsAccountWritePlatformService; private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository; private final BusinessEventNotifierService businessEventNotifierService; - + private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService; + @Autowired public SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final SavingsAccountRepositoryWrapper savingAccountRepository, final SavingsAccountAssembler savingAccountAssembler, @@ -119,7 +110,8 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl final SavingsAccountDomainService savingsAccountDomainService, final SavingsAccountWritePlatformService savingsAccountWritePlatformService, final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository, - final BusinessEventNotifierService businessEventNotifierService) { + final BusinessEventNotifierService businessEventNotifierService, + final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService) { this.context = context; this.savingAccountRepository = savingAccountRepository; this.savingAccountAssembler = savingAccountAssembler; @@ -137,6 +129,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl this.accountNumberFormatRepository = accountNumberFormatRepository; this.savingsAccountWritePlatformService = savingsAccountWritePlatformService; this.businessEventNotifierService = businessEventNotifierService ; + this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService; } /* @@ -179,6 +172,15 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl generateAccountNumber(account); final Long savingsId = account.getId(); + if(command.parameterExists(SavingsApiConstants.datatables)){ + this.entityDatatableChecksWritePlatformService.saveDatatables(StatusEnum.CREATE.getCode().longValue(), + EntityTables.SAVING.getName(), savingsId, account.productId(), + command.arrayOfParameterNamed(SavingsApiConstants.datatables)); + } + this.entityDatatableChecksWritePlatformService.runTheCheckForProduct(savingsId, + EntityTables.SAVING.getName(), StatusEnum.CREATE.getCode().longValue(), + EntityTables.SAVING.getForeignKeyColumnNameOnDatatable(), account.productId()); + return new CommandProcessingResultBuilder() // .withCommandId(command.commandId()) // .withEntityId(savingsId) // @@ -343,6 +345,11 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId); checkClientOrGroupActive(savingsAccount); + entityDatatableChecksWritePlatformService.runTheCheckForProduct(savingsId, EntityTables.SAVING.getName(), + StatusEnum.APPROVE.getCode().longValue(),EntityTables.SAVING.getForeignKeyColumnNameOnDatatable(), + savingsAccount.productId()); + + final Map changes = savingsAccount.approveApplication(currentUser, command, DateUtils.getLocalDateOfTenant()); if (!changes.isEmpty()) { this.savingAccountRepository.save(savingsAccount); @@ -411,6 +418,10 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId); checkClientOrGroupActive(savingsAccount); + entityDatatableChecksWritePlatformService.runTheCheckForProduct(savingsId, EntityTables.SAVING.getName(), + StatusEnum.REJECTED.getCode().longValue(),EntityTables.SAVING.getForeignKeyColumnNameOnDatatable(), + savingsAccount.productId()); + final Map changes = savingsAccount.rejectApplication(currentUser, command, DateUtils.getLocalDateOfTenant()); if (!changes.isEmpty()) { this.savingAccountRepository.save(savingsAccount); @@ -445,6 +456,10 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId); checkClientOrGroupActive(savingsAccount); + entityDatatableChecksWritePlatformService.runTheCheckForProduct(savingsId, EntityTables.SAVING.getName(), + StatusEnum.WITHDRAWN.getCode().longValue(),EntityTables.SAVING.getForeignKeyColumnNameOnDatatable(), + savingsAccount.productId()); + final Map changes = savingsAccount.applicantWithdrawsFromApplication(currentUser, command, DateUtils.getLocalDateOfTenant()); if (!changes.isEmpty()) { diff --git a/fineract-provider/src/main/resources/sql/migrations/core_db/V324__datatable_checks.sql b/fineract-provider/src/main/resources/sql/migrations/core_db/V324__datatable_checks.sql new file mode 100644 index 000000000..6ba065813 --- /dev/null +++ b/fineract-provider/src/main/resources/sql/migrations/core_db/V324__datatable_checks.sql @@ -0,0 +1,46 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +CREATE TABLE `m_entity_datatable_check` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `application_table_name` VARCHAR(200) NOT NULL, + `x_registered_table_name` VARCHAR(50) NOT NULL, + `status_enum` INT(11) NOT NULL, + `system_defined` TINYINT(4) NOT NULL DEFAULT '0', + `product_id` BIGINT(10) NULL DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE INDEX `unique_entity_check` (`application_table_name`, `x_registered_table_name`, `status_enum`, `product_id`), + INDEX `x_registered_table_name` (`x_registered_table_name`), + INDEX `product_id` (`product_id`), + CONSTRAINT `m_entity_datatable_check_ibfk_1` FOREIGN KEY (`x_registered_table_name`) + REFERENCES `x_registered_table` (`registered_table_name`) +) +COLLATE='utf8_general_ci' +ENGINE=InnoDB +; + + +INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker) +VALUE ("datatable","READ_ENTITY_DATATABLE_CHECK","ENTITY_DATATABLE_CHECK","READ",0); + +INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker) +VALUE ("datatable","CREATE_ENTITY_DATATABLE_CHECK","ENTITY_DATATABLE_CHECK","CREATE",0); + +INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker) +VALUE ("datatable","DELETE_ENTITY_DATATABLE_CHECK","ENTITY_DATATABLE_CHECK","DELETE",0);