Entity datatable check implementation

This commit is contained in:
Satish
2016-12-08 09:48:28 +05:30
parent b60779b9a0
commit dde6eaec2a
51 changed files with 2133 additions and 289 deletions
@@ -2756,6 +2756,24 @@ public class CommandWrapperBuilder {
return this; 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() { public CommandWrapperBuilder addSelfServiceBeneficiaryTPT() {
this.actionName = "CREATE"; this.actionName = "CREATE";
this.entityName = "SSBENEFICIARYTPT"; this.entityName = "SSBENEFICIARYTPT";
@@ -278,6 +278,26 @@ public class DataValidatorBuilder {
return this; return this;
} }
public DataValidatorBuilder isOneOfTheseStringValues(final List<String> 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) { public DataValidatorBuilder isNotOneOfTheseValues(final Object... values) {
if (this.value == null && this.ignoreNullValue) { return this; } if (this.value == null && this.ignoreNullValue) { return this; }
@@ -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<GenericResultsetData> 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<GenericResultsetData> 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<EntityDataTableChecksData> 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);
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -45,4 +45,19 @@ public class DatatableData {
this.columnHeaderData = columnHeaderData; 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;
}
} }
@@ -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;
}
}
@@ -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<String> entities;
private final List<DatatableCheckStatusData> statusClient;
private final List<DatatableCheckStatusData> statusGroup;
private final List<DatatableCheckStatusData> statusSavings;
private final List<DatatableCheckStatusData> statusLoans;
private final List<DatatableChecksData> datatables;
private final Collection<LoanProductData> loanProductDatas;
private final Collection<SavingsProductData> savingsProductDatas;
public EntityDataTableChecksTemplateData(final List<String> entities, List<DatatableCheckStatusData> statusClient,
List<DatatableCheckStatusData> statusGroup, List<DatatableCheckStatusData> statusSavings,
List<DatatableCheckStatusData> statusLoans, List<DatatableChecksData> datatables,
Collection<LoanProductData> loanProductDatas, Collection<SavingsProductData> 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;
}
}
@@ -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<String, EntityTables> lookup = new HashMap<String, EntityTables>();
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<String> getEntitiesList() {
List<String> data = new ArrayList<String>();
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;
}
}
@@ -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<DatatableCheckStatusData> getStatusList() {
List<DatatableCheckStatusData> data = new ArrayList<DatatableCheckStatusData>();
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;
}
}
@@ -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<Long> {
@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;
}
}
@@ -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<EntityDatatableChecks, Long>,
JpaSpecificationExecutor<EntityDatatableChecks> {
public List<EntityDatatableChecks> 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<EntityDatatableChecks> 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<EntityDatatableChecks> 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<EntityDatatableChecks> 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<EntityDatatableChecks> findByEntityStatusAndDatatableIdAndNoProduct(@Param("entity") String entityName,
@Param("status") Long status, @Param("datatableName") String datatableName);
}
@@ -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<ApiParameterError> 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);
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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());
}
}
@@ -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<String> 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<Map<String, Object>>() {
}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters);
final List<ApiParameterError> 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<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
}
}
@@ -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<EntityDataTableChecksData> 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<EntityDataTableChecksData> 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<DatatableData> retrieveTemplates(final Long status, final String entity, final Long productId) {
List<EntityDatatableChecks> 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<DatatableData> ret = new ArrayList<>();
for (EntityDatatableChecks t : tableRequiredBeforeAction) {
ret.add(this.readWriteNonCoreDataService.retrieveDatatable(t.getDatatableName()));
}
return ret;
}
return null;
}
@Override
public EntityDataTableChecksTemplateData retrieveTemplate() {
List<DatatableChecksData> dataTables = getDataTables();
List<String> entities = EntityTables.getEntitiesList();
List<DatatableCheckStatusData> statusClient = getStatusList(EntityTables.getStatus("m_client"));
List<DatatableCheckStatusData> statusLoan = getStatusList(EntityTables.getStatus("m_loan"));
List<DatatableCheckStatusData> statusGroup = getStatusList(EntityTables.getStatus("m_group"));
List<DatatableCheckStatusData> statusSavings = getStatusList(EntityTables.getStatus("m_savings_account"));
Collection<LoanProductData> loanProductDatas = this.loanProductReadPlatformService.retrieveAllLoanProductsForLookup(true);
Collection<SavingsProductData> savingsProductDatas = this.savingsProductReadPlatformService.retrieveAllForLookup();
return new EntityDataTableChecksTemplateData(entities, statusClient, statusGroup, statusSavings, statusLoan, dataTables,
loanProductDatas, savingsProductDatas);
}
private List<DatatableCheckStatusData> getStatusList(Integer[] statuses) {
List<DatatableCheckStatusData> 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<DatatableChecksData> getDataTables() {
final String sql = "select " + this.registerDataTableMapper.schema();
return this.jdbcTemplate.query(sql, this.registerDataTableMapper);
}
protected static final class RegisterDataTableMapper implements RowMapper<DatatableChecksData> {
@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<EntityDataTableChecksData> {
@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' ";
}
}
}
@@ -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<DatatableData> retrieveTemplates(Long status, String entity, Long productId);
Page<EntityDataTableChecksData> retrieveAll(SearchParameters searchParameters, Long status, String entity, Long productLoanId);
}
@@ -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);
}
@@ -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<EntityDatatableChecks> 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<EntityDatatableChecks> tableRequiredBeforeClientActivation = entityDatatableChecksRepository
.findByEntityAndStatus(entityName, statusCode);
if (tableRequiredBeforeClientActivation != null) {
List<String> 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<EntityDatatableChecks> tableRequiredBeforAction = entityDatatableChecksRepository
.findByEntityStatusAndProduct(entityName, statusCode, productId);
if (tableRequiredBeforAction == null || tableRequiredBeforAction.size() < 1) {
tableRequiredBeforAction = entityDatatableChecksRepository.findByEntityStatusAndNoProduct(entityName,
statusCode);
}
if (tableRequiredBeforAction != null) {
List<String> 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<ApiParameterError> 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<ApiParameterError> errors = e.getErrors();
for(ApiParameterError error : e.getErrors()){
error.setParameterName("datatables."+datatableName+"."+error.getParameterName());
}
throw e;
}
}
}
return isMakerCheckerEnabled;
}
private List<String> getDatatableNames(Long status, String entity, Long productId) {
List<String> ret = new ArrayList<>();
List<EntityDatatableChecks> 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());
}
}
@@ -54,6 +54,8 @@ public interface ReadWriteNonCoreDataService {
CommandProcessingResult createNewDatatableEntry(String datatable, Long appTableId, JsonCommand command); 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 createPPIEntry(String datatable, Long appTableId, JsonCommand command);
CommandProcessingResult updateDatatableEntryOneToOne(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); String getDataTableName(String Url);
Long countDatatableEntries(String datatableName,Long appTableId,String foreignKeyColumn);
} }
@@ -20,13 +20,7 @@ package org.apache.fineract.infrastructure.dataqueries.service;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.*;
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 javax.persistence.PersistenceException; import javax.persistence.PersistenceException;
import javax.sql.DataSource; 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.serialization.JsonParserHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource; import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.dataqueries.api.DataTableApiConstant; import org.apache.fineract.infrastructure.dataqueries.api.DataTableApiConstant;
import org.apache.fineract.infrastructure.dataqueries.data.DataTableValidator; import org.apache.fineract.infrastructure.dataqueries.data.*;
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.exception.DatatableNotFoundException; import org.apache.fineract.infrastructure.dataqueries.exception.DatatableNotFoundException;
import org.apache.fineract.infrastructure.dataqueries.exception.DatatableSystemErrorException; import org.apache.fineract.infrastructure.dataqueries.exception.DatatableSystemErrorException;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
@@ -359,7 +349,12 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
@Transactional @Transactional
@Override @Override
public CommandProcessingResult createNewDatatableEntry(final String dataTableName, final Long appTableId, final JsonCommand command) { 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 { try {
final String appTable = queryForApplicationTableName(dataTableName); final String appTable = queryForApplicationTableName(dataTableName);
final CommandProcessingResult commandProcessingResult = checkMainResourceExistsWithinScope(appTable, appTableId); final CommandProcessingResult commandProcessingResult = checkMainResourceExistsWithinScope(appTable, appTableId);
@@ -367,7 +362,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
final List<ResultsetColumnHeaderData> columnHeaders = this.genericDataService.fillResultsetColumnHeaders(dataTableName); final List<ResultsetColumnHeaderData> columnHeaders = this.genericDataService.fillResultsetColumnHeaders(dataTableName);
final Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType(); final Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType();
final Map<String, String> dataParams = this.fromJsonHelper.extractDataMap(typeOfMap, command.json()); final Map<String, String> dataParams = this.fromJsonHelper.extractDataMap(typeOfMap, json);
final String sql = getAddSql(columnHeaders, dataTableName, getFKField(appTable), appTableId, dataParams); final String sql = getAddSql(columnHeaders, dataTableName, getFKField(appTable), appTableId, dataParams);
@@ -378,29 +373,32 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
} catch (final DataAccessException dve) { } catch (final DataAccessException dve) {
final Throwable cause = dve.getCause() ; final Throwable cause = dve.getCause() ;
final Throwable realCause = dve.getMostSpecificCause(); final Throwable realCause = dve.getMostSpecificCause();
if (realCause.getMessage() if (realCause.getMessage().contains("Duplicate entry") || cause.getMessage().contains("Duplicate entry")) {
.contains("Duplicate entry") || cause.getMessage() throw new PlatformDataIntegrityException("error.msg.datatable.entry.duplicate", "An entry already exists for datatable `"
.contains("Duplicate entry")) { throw new PlatformDataIntegrityException( + dataTableName + "` and application table with identifier `" + appTableId + "`.", "dataTableName", dataTableName,
"error.msg.datatable.entry.duplicate", "An entry already exists for datatable `" + dataTableName appTableId);
+ "` and application table with identifier `" + appTableId + "`.", } else if (realCause.getMessage().contains("doesn't have a default value")
"dataTableName", dataTableName, appTableId); } || 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); logAsErrorUnexpectedDataIntegrityException(dve);
throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue", throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue",
"Unknown data integrity issue with resource."); "Unknown data integrity issue with resource.");
}catch(final PersistenceException e) { } catch (final PersistenceException e) {
final Throwable cause = e.getCause() ; final Throwable cause = e.getCause();
if (cause.getMessage() if (cause.getMessage().contains("Duplicate entry")) {
.contains("Duplicate entry")) { throw new PlatformDataIntegrityException("error.msg.datatable.entry.duplicate", "An entry already exists for datatable `"
throw new PlatformDataIntegrityException( + dataTableName + "` and application table with identifier `" + appTableId + "`.", "dataTableName", dataTableName,
"error.msg.datatable.entry.duplicate", "An entry already exists for datatable `" + dataTableName appTableId);
+ "` and application table with identifier `" + appTableId + "`.", } else if (cause.getMessage().contains("doesn't have a default value")) { throw new PlatformDataIntegrityException(
"dataTableName", dataTableName, appTableId); } "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); logAsErrorUnexpectedDataIntegrityException(e);
throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue", throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue",
"Unknown data integrity issue with resource."); "Unknown data integrity issue with resource.");
} }
} }
@@ -1722,4 +1720,14 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
return true; 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;
}
} }
@@ -177,16 +177,18 @@ public class ClientApiConstants {
public static final String officeOptionsParamName = "officeOptions"; public static final String officeOptionsParamName = "officeOptions";
public static final String staffOptionsParamName = "staffOptions"; public static final String staffOptionsParamName = "staffOptions";
public static final String datatables = "datatables";
public static final Set<String> CLIENT_CREATE_REQUEST_DATA_PARAMETERS = new HashSet<>( public static final Set<String> CLIENT_CREATE_REQUEST_DATA_PARAMETERS = new HashSet<>(
Arrays.asList(address,localeParamName, dateFormatParamName, groupIdParamName, accountNoParamName, externalIdParamName, Arrays.asList(address,localeParamName, dateFormatParamName, groupIdParamName, accountNoParamName, externalIdParamName,
mobileNoParamName, firstnameParamName, middlenameParamName, lastnameParamName, fullnameParamName, officeIdParamName, mobileNoParamName, firstnameParamName, middlenameParamName, lastnameParamName, fullnameParamName, officeIdParamName,
activeParamName, activationDateParamName, staffIdParamName, submittedOnDateParamName, savingsProductIdParamName, activeParamName, activationDateParamName, staffIdParamName, submittedOnDateParamName, savingsProductIdParamName,
dateOfBirthParamName, genderIdParamName, clientTypeIdParamName, clientClassificationIdParamName, dateOfBirthParamName, genderIdParamName, clientTypeIdParamName, clientClassificationIdParamName,
clientNonPersonDetailsParamName, displaynameParamName, legalFormIdParamName)); clientNonPersonDetailsParamName, displaynameParamName, legalFormIdParamName, datatables));
public static final Set<String> CLIENT_NON_PERSON_CREATE_REQUEST_DATA_PARAMETERS = new HashSet<>( public static final Set<String> CLIENT_NON_PERSON_CREATE_REQUEST_DATA_PARAMETERS = new HashSet<>(
Arrays.asList(address,localeParamName, dateFormatParamName, incorpNumberParamName, remarksParamName, incorpValidityTillParamName, Arrays.asList(address,localeParamName, dateFormatParamName, incorpNumberParamName, remarksParamName, incorpValidityTillParamName,
constitutionIdParamName, mainBusinessLineIdParamName)); constitutionIdParamName, mainBusinessLineIdParamName, datatables));
public static final Set<String> CLIENT_UPDATE_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName, public static final Set<String> CLIENT_UPDATE_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName,
dateFormatParamName, accountNoParamName, externalIdParamName, mobileNoParamName, firstnameParamName, middlenameParamName, dateFormatParamName, accountNoParamName, externalIdParamName, mobileNoParamName, firstnameParamName, middlenameParamName,
@@ -27,6 +27,7 @@ import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.fineract.infrastructure.codes.data.CodeValueData; import org.apache.fineract.infrastructure.codes.data.CodeValueData;
import org.apache.fineract.infrastructure.core.data.EnumOptionData; 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.office.data.OfficeData;
import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.organisation.staff.data.StaffData;
import org.apache.fineract.portfolio.address.data.AddressData; import org.apache.fineract.portfolio.address.data.AddressData;
@@ -101,12 +102,14 @@ final public class ClientData implements Comparable<ClientData> {
private final Boolean isAddressEnabled; private final Boolean isAddressEnabled;
private final List<DatatableData> datatables;
public static ClientData template(final Long officeId, final LocalDate joinedDate, final Collection<OfficeData> officeOptions, public static ClientData template(final Long officeId, final LocalDate joinedDate, final Collection<OfficeData> officeOptions,
final Collection<StaffData> staffOptions, final Collection<CodeValueData> narrations, final Collection<StaffData> staffOptions, final Collection<CodeValueData> narrations,
final Collection<CodeValueData> genderOptions, final Collection<SavingsProductData> savingProductOptions, final Collection<CodeValueData> genderOptions, final Collection<SavingsProductData> savingProductOptions,
final Collection<CodeValueData> clientTypeOptions, final Collection<CodeValueData> clientClassificationOptions, final Collection<CodeValueData> clientTypeOptions, final Collection<CodeValueData> clientClassificationOptions, final Collection<CodeValueData> clientNonPersonConstitutionOptions,
final Collection<CodeValueData> clientNonPersonConstitutionOptions, final Collection<CodeValueData> clientNonPersonMainBusinessLineOptions, final Collection<CodeValueData> clientNonPersonMainBusinessLineOptions, final List<EnumOptionData> clientLegalFormOptions, final AddressData address,
final List<EnumOptionData> clientLegalFormOptions, final AddressData address,final Boolean isAddressEnabled) { final Boolean isAddressEnabled, final List<DatatableData> datatables) {
final String accountNo = null; final String accountNo = null;
final EnumOptionData status = null; final EnumOptionData status = null;
final CodeValueData subStatus = null; final CodeValueData subStatus = null;
@@ -141,7 +144,7 @@ final public class ClientData implements Comparable<ClientData> {
staffName, officeOptions, groups, staffOptions, narrations, genderOptions, timeline, savingProductOptions, staffName, officeOptions, groups, staffOptions, narrations, genderOptions, timeline, savingProductOptions,
savingsProductId, savingsProductName, savingsAccountId, savingAccountOptions, clientType, clientClassification, savingsProductId, savingsProductName, savingsAccountId, savingAccountOptions, clientType, clientClassification,
clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, 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> {
clientData.savingsProductName, clientData.savingsAccountId, clientData.savingAccountOptions, clientData.clientType, clientData.savingsProductName, clientData.savingsAccountId, clientData.savingAccountOptions, clientData.clientType,
clientData.clientClassification, templateData.clientTypeOptions, templateData.clientClassificationOptions, clientData.clientClassification, templateData.clientTypeOptions, templateData.clientClassificationOptions,
templateData.clientNonPersonConstitutionOptions, templateData.clientNonPersonMainBusinessLineOptions, clientData.clientNonPersonDetails, 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> {
clientData.savingsProductName, clientData.savingsAccountId, savingAccountOptions, clientData.clientType, clientData.savingsProductName, clientData.savingsAccountId, savingAccountOptions, clientData.clientType,
clientData.clientClassification, clientData.clientTypeOptions, clientData.clientClassificationOptions, clientData.clientClassification, clientData.clientTypeOptions, clientData.clientClassificationOptions,
clientData.clientNonPersonConstitutionOptions, clientData.clientNonPersonMainBusinessLineOptions, clientData.clientNonPersonDetails, 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> {
clientData.savingAccountOptions, clientData.clientType, clientData.clientClassification, clientData.clientTypeOptions, clientData.savingAccountOptions, clientData.clientType, clientData.clientClassification, clientData.clientTypeOptions,
clientData.clientClassificationOptions, clientData.clientNonPersonConstitutionOptions, clientData.clientNonPersonMainBusinessLineOptions, clientData.clientClassificationOptions, clientData.clientNonPersonConstitutionOptions, clientData.clientNonPersonMainBusinessLineOptions,
clientData.clientNonPersonDetails, clientData.clientLegalFormOptions, clientData.legalForm,clientData.address, clientData.clientNonPersonDetails, clientData.clientLegalFormOptions, clientData.legalForm,clientData.address,
clientData.isAddressEnabled); clientData.isAddressEnabled, null);
} }
@@ -230,7 +233,7 @@ final public class ClientData implements Comparable<ClientData> {
staffName, allowedOffices, groups, staffOptions, closureReasons, genderOptions, timeline, savingProductOptions, staffName, allowedOffices, groups, staffOptions, closureReasons, genderOptions, timeline, savingProductOptions,
savingsProductId, savingsProductName, savingsAccountId, savingAccountOptions, clientType, clientClassification, savingsProductId, savingsProductName, savingsAccountId, savingAccountOptions, clientType, clientClassification,
clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, 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) { 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<ClientData> {
staffName, allowedOffices, groups, staffOptions, closureReasons, genderOptions, timeline, savingProductOptions, staffName, allowedOffices, groups, staffOptions, closureReasons, genderOptions, timeline, savingProductOptions,
savingsProductId, savingsProductName, savingsAccountId, savingAccountOptions, clientType, clientClassification, savingsProductId, savingsProductName, savingsAccountId, savingAccountOptions, clientType, clientClassification,
clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, 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<ClientData> {
staffName, allowedOffices, groups, staffOptions, closureReasons, genderOptions, timeline, savingProductOptions, staffName, allowedOffices, groups, staffOptions, closureReasons, genderOptions, timeline, savingProductOptions,
savingsProductId, savingsProductName, savingsAccountId, null, clientType, clientClassification, clientTypeOptions, savingsProductId, savingsProductName, savingsAccountId, null, clientType, clientClassification, clientTypeOptions,
clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, clientNonPerson, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, clientNonPerson,
clientLegalFormOptions, legalForm,null,null); clientLegalFormOptions, legalForm,null,null, null);
} }
@@ -321,7 +324,8 @@ final public class ClientData implements Comparable<ClientData> {
final CodeValueData clientClassification, final Collection<CodeValueData> clientTypeOptions, final CodeValueData clientClassification, final Collection<CodeValueData> clientTypeOptions,
final Collection<CodeValueData> clientClassificationOptions, final Collection<CodeValueData> clientNonPersonConstitutionOptions, final Collection<CodeValueData> clientClassificationOptions, final Collection<CodeValueData> clientNonPersonConstitutionOptions,
final Collection<CodeValueData> clientNonPersonMainBusinessLineOptions, final ClientNonPersonData clientNonPerson, final Collection<CodeValueData> clientNonPersonMainBusinessLineOptions, final ClientNonPersonData clientNonPerson,
final List<EnumOptionData> clientLegalFormOptions, final EnumOptionData legalForm,final AddressData address, final Boolean isAddressEnabled) { final List<EnumOptionData> clientLegalFormOptions, final EnumOptionData legalForm, final AddressData address,
final Boolean isAddressEnabled, final List<DatatableData> datatables) {
this.accountNo = accountNo; this.accountNo = accountNo;
this.status = status; this.status = status;
if (status != null) { if (status != null) {
@@ -382,7 +386,8 @@ final public class ClientData implements Comparable<ClientData> {
this.clientNonPersonDetails = clientNonPerson; this.clientNonPersonDetails = clientNonPerson;
this.address = address; this.address = address;
this.isAddressEnabled = isAddressEnabled; this.isAddressEnabled = isAddressEnabled;
this.datatables = datatables;
} }
@@ -27,6 +27,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import com.google.gson.JsonArray;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.ApiParameterError; 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); final Long savingsProductId = this.fromApiJsonHelper.extractLongNamed(ClientApiConstants.savingsProductIdParamName, element);
baseDataValidator.reset().parameter(ClientApiConstants.savingsProductIdParamName).value(savingsProductId).ignoreIfNull() baseDataValidator.reset().parameter(ClientApiConstants.savingsProductIdParamName).value(savingsProductId).ignoreIfNull()
.longGreaterThanZero(); .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)) { if (isFullnameProvided(element) || isIndividualNameProvided(element)) {
@@ -154,6 +162,10 @@ public final class ClientDataValidator {
final LocalDate joinedDate = this.fromApiJsonHelper.extractLocalDateNamed(ClientApiConstants.activationDateParamName, final LocalDate joinedDate = this.fromApiJsonHelper.extractLocalDateNamed(ClientApiConstants.activationDateParamName,
element); element);
baseDataValidator.reset().parameter(ClientApiConstants.activationDateParamName).value(joinedDate).notNull(); 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 { } else {
baseDataValidator.reset().parameter(ClientApiConstants.activeParamName).value(active).trueOrFalseRequired(false); 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); final Integer legalFormId = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(ClientApiConstants.legalFormIdParamName, element);
baseDataValidator.reset().parameter(ClientApiConstants.legalFormIdParamName).value(legalFormId).ignoreIfNull().inMinMaxRange(1, 2); baseDataValidator.reset().parameter(ClientApiConstants.legalFormIdParamName).value(legalFormId).ignoreIfNull().inMinMaxRange(1, 2);
} }
List<ApiParameterError> 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<ApiParameterError> dataValidationErrorsForClientNonPerson = getDataValidationErrorsForCreateOnClientNonPerson(element.getAsJsonObject().get(ClientApiConstants.clientNonPersonDetailsParamName));
dataValidationErrors.addAll(dataValidationErrorsForClientNonPerson); dataValidationErrors.addAll(dataValidationErrorsForClientNonPerson);
throwExceptionIfValidationWarningsExist(dataValidationErrors); throwExceptionIfValidationWarningsExist(dataValidationErrors);
@@ -236,8 +253,8 @@ public final class ClientDataValidator {
element); element);
baseDataValidator.reset().parameter(ClientApiConstants.mainBusinessLineIdParamName).value(mainBusinessLine).integerGreaterThanZero(); baseDataValidator.reset().parameter(ClientApiConstants.mainBusinessLineIdParamName).value(mainBusinessLine).integerGreaterThanZero();
} }
return dataValidationErrors; return dataValidationErrors;
} }
private void validateIndividualNamePartsCannotBeUsedWithFullname(final JsonElement element, final DataValidatorBuilder baseDataValidator) { private void validateIndividualNamePartsCannotBeUsedWithFullname(final JsonElement element, final DataValidatorBuilder baseDataValidator) {
@@ -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.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource; import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters; 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.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.office.data.OfficeData; import org.apache.fineract.organisation.office.data.OfficeData;
import org.apache.fineract.organisation.office.service.OfficeReadPlatformService; import org.apache.fineract.organisation.office.service.OfficeReadPlatformService;
@@ -81,6 +85,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
private final AddressReadPlatformService addressReadPlatformService; private final AddressReadPlatformService addressReadPlatformService;
private final ConfigurationReadPlatformService configurationReadPlatformService; private final ConfigurationReadPlatformService configurationReadPlatformService;
private final EntityDatatableChecksReadService entityDatatableChecksReadService;
@Autowired @Autowired
public ClientReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource, public ClientReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
@@ -88,7 +93,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final CodeValueReadPlatformService codeValueReadPlatformService, final CodeValueReadPlatformService codeValueReadPlatformService,
final SavingsProductReadPlatformService savingsProductReadPlatformService, final SavingsProductReadPlatformService savingsProductReadPlatformService,
final AddressReadPlatformService addressReadPlatformService, final AddressReadPlatformService addressReadPlatformService,
final ConfigurationReadPlatformService configurationReadPlatformService) { final ConfigurationReadPlatformService configurationReadPlatformService,
final EntityDatatableChecksReadService entityDatatableChecksReadService) {
this.context = context; this.context = context;
this.officeReadPlatformService = officeReadPlatformService; this.officeReadPlatformService = officeReadPlatformService;
this.jdbcTemplate = new JdbcTemplate(dataSource); this.jdbcTemplate = new JdbcTemplate(dataSource);
@@ -97,6 +103,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
this.savingsProductReadPlatformService = savingsProductReadPlatformService; this.savingsProductReadPlatformService = savingsProductReadPlatformService;
this.addressReadPlatformService=addressReadPlatformService; this.addressReadPlatformService=addressReadPlatformService;
this.configurationReadPlatformService=configurationReadPlatformService; this.configurationReadPlatformService=configurationReadPlatformService;
this.entityDatatableChecksReadService = entityDatatableChecksReadService;
} }
@Override @Override
@@ -149,9 +156,12 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final List<EnumOptionData> clientLegalFormOptions = ClientEnumerations.legalForm(LegalForm.values()); final List<EnumOptionData> clientLegalFormOptions = ClientEnumerations.legalForm(LegalForm.values());
final List<DatatableData> datatableTemplates = this.entityDatatableChecksReadService
.retrieveTemplates(StatusEnum.CREATE.getCode().longValue(), EntityTables.CLIENT.getName(), null);
return ClientData.template(defaultOfficeId, new LocalDate(), offices, staffOptions, null, genderOptions, savingsProductDatas, return ClientData.template(defaultOfficeId, new LocalDate(), offices, staffOptions, null, genderOptions, savingsProductDatas,
clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions,
clientLegalFormOptions,address,isAddressEnabled); clientLegalFormOptions,address,isAddressEnabled, datatableTemplates);
} }
@Override @Override
@@ -782,7 +792,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final Collection<CodeValueData> clientNonPersonMainBusinessLineOptions = null; final Collection<CodeValueData> clientNonPersonMainBusinessLineOptions = null;
final List<EnumOptionData> clientLegalFormOptions = null; final List<EnumOptionData> clientLegalFormOptions = null;
return ClientData.template(null, null, null, null, narrations, null, null, clientTypeOptions, clientClassificationOptions, return ClientData.template(null, null, null, null, narrations, null, null, clientTypeOptions, clientClassificationOptions,
clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, clientLegalFormOptions,null,null); clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, clientLegalFormOptions,null,null, null);
} }
} }
@@ -18,12 +18,7 @@
*/ */
package org.apache.fineract.portfolio.client.service; package org.apache.fineract.portfolio.client.service;
import java.util.*;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.persistence.PersistenceException; 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.data.CommandProcessingResultBuilder;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; 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.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.office.domain.Office; import org.apache.fineract.organisation.office.domain.Office;
import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper; 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.address.service.AddressWritePlatformService;
import org.apache.fineract.portfolio.client.api.ClientApiConstants; import org.apache.fineract.portfolio.client.api.ClientApiConstants;
import org.apache.fineract.portfolio.client.data.ClientDataValidator; import org.apache.fineract.portfolio.client.data.ClientDataValidator;
import org.apache.fineract.portfolio.client.domain.AccountNumberGenerator; import org.apache.fineract.portfolio.client.domain.*;
import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.portfolio.client.exception.*;
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.common.BusinessEventNotificationConstants.BUSINESS_ENTITY; import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY;
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS; import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS;
import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService; import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService;
@@ -121,7 +109,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
private final ConfigurationReadPlatformService configurationReadPlatformService; private final ConfigurationReadPlatformService configurationReadPlatformService;
private final AddressWritePlatformService addressWritePlatformService; private final AddressWritePlatformService addressWritePlatformService;
private final BusinessEventNotifierService businessEventNotifierService; private final BusinessEventNotifierService businessEventNotifierService;
private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
@Autowired @Autowired
public ClientWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, public ClientWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
final ClientRepositoryWrapper clientRepository, final ClientNonPersonRepositoryWrapper clientNonPersonRepository, final ClientRepositoryWrapper clientRepository, final ClientNonPersonRepositoryWrapper clientNonPersonRepository,
@@ -134,7 +122,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
final CommandProcessingService commandProcessingService, final ConfigurationDomainService configurationDomainService, final CommandProcessingService commandProcessingService, final ConfigurationDomainService configurationDomainService,
final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository, final FromJsonHelper fromApiJsonHelper, final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository, final FromJsonHelper fromApiJsonHelper,
final ConfigurationReadPlatformService configurationReadPlatformService, final ConfigurationReadPlatformService configurationReadPlatformService,
final AddressWritePlatformService addressWritePlatformService, final BusinessEventNotifierService businessEventNotifierService) { final AddressWritePlatformService addressWritePlatformService, final BusinessEventNotifierService businessEventNotifierService,
final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService) {
this.context = context; this.context = context;
this.clientRepository = clientRepository; this.clientRepository = clientRepository;
this.clientNonPersonRepository = clientNonPersonRepository; this.clientNonPersonRepository = clientNonPersonRepository;
@@ -156,6 +145,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
this.configurationReadPlatformService = configurationReadPlatformService; this.configurationReadPlatformService = configurationReadPlatformService;
this.addressWritePlatformService = addressWritePlatformService; this.addressWritePlatformService = addressWritePlatformService;
this.businessEventNotifierService = businessEventNotifierService; this.businessEventNotifierService = businessEventNotifierService;
this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService;
} }
@Transactional @Transactional
@@ -314,6 +304,15 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
this.addressWritePlatformService.addNewClientAddress(newClient, command); 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() // return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) // .withCommandId(command.commandId()) //
.withOfficeId(clientOffice.getId()) // .withOfficeId(clientOffice.getId()) //
@@ -534,6 +533,9 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
final LocalDate activationDate = command.localDateValueOfParameterNamed("activationDate"); 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(); final AppUser currentUser = this.context.authenticatedUser();
client.activate(currentUser, fmt, activationDate); client.activate(currentUser, fmt, activationDate);
CommandProcessingResult result = openSavingsAccount(client, fmt); 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, throw new InvalidClientStateTransitionException("close", "date.cannot.before.client.actvation.date", errorMessage,
closureDate, client.getActivationLocalDate()); closureDate, client.getActivationLocalDate());
} }
entityDatatableChecksWritePlatformService.runTheCheck(clientId,EntityTables.CLIENT.getName(),
StatusEnum.CLOSE.getCode().longValue(),EntityTables.CLIENT.getForeignKeyColumnNameOnDatatable());
final List<Loan> clientLoans = this.loanRepositoryWrapper.findLoanByClientId(clientId); final List<Loan> clientLoans = this.loanRepositoryWrapper.findLoanByClientId(clientId);
for (final Loan loan : clientLoans) { for (final Loan loan : clientLoans) {
final LoanStatusMapper loanStatus = new LoanStatusMapper(loan.status().getValue()); final LoanStatusMapper loanStatus = new LoanStatusMapper(loan.status().getValue());
@@ -18,11 +18,7 @@
*/ */
package org.apache.fineract.portfolio.group.api; package org.apache.fineract.portfolio.group.api;
import java.util.Arrays; import java.util.*;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; 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.serialization.ToApiJsonSerializer;
import org.apache.fineract.infrastructure.core.service.Page; import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.SearchParameters; 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.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.portfolio.accountdetails.data.AccountSummaryCollectionData; import org.apache.fineract.portfolio.accountdetails.data.AccountSummaryCollectionData;
import org.apache.fineract.portfolio.accountdetails.service.AccountDetailsReadPlatformService; import org.apache.fineract.portfolio.accountdetails.service.AccountDetailsReadPlatformService;
@@ -92,6 +92,7 @@ public class CentersApiResource {
private final AccountDetailsReadPlatformService accountDetailsReadPlatformService; private final AccountDetailsReadPlatformService accountDetailsReadPlatformService;
private final CalendarReadPlatformService calendarReadPlatformService; private final CalendarReadPlatformService calendarReadPlatformService;
private final MeetingReadPlatformService meetingReadPlatformService; private final MeetingReadPlatformService meetingReadPlatformService;
private final EntityDatatableChecksReadService entityDatatableChecksReadService;
@Autowired @Autowired
public CentersApiResource(final PlatformSecurityContext context, final CenterReadPlatformService centerReadPlatformService, public CentersApiResource(final PlatformSecurityContext context, final CenterReadPlatformService centerReadPlatformService,
@@ -101,7 +102,8 @@ public class CentersApiResource {
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService, final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
final CollectionSheetReadPlatformService collectionSheetReadPlatformService, final FromJsonHelper fromJsonHelper, final CollectionSheetReadPlatformService collectionSheetReadPlatformService, final FromJsonHelper fromJsonHelper,
final AccountDetailsReadPlatformService accountDetailsReadPlatformService, final AccountDetailsReadPlatformService accountDetailsReadPlatformService,
final CalendarReadPlatformService calendarReadPlatformService, final MeetingReadPlatformService meetingReadPlatformService) { final CalendarReadPlatformService calendarReadPlatformService, final MeetingReadPlatformService meetingReadPlatformService,
final EntityDatatableChecksReadService entityDatatableChecksReadService) {
this.context = context; this.context = context;
this.centerReadPlatformService = centerReadPlatformService; this.centerReadPlatformService = centerReadPlatformService;
this.centerApiJsonSerializer = centerApiJsonSerializer; this.centerApiJsonSerializer = centerApiJsonSerializer;
@@ -114,6 +116,7 @@ public class CentersApiResource {
this.accountDetailsReadPlatformService = accountDetailsReadPlatformService; this.accountDetailsReadPlatformService = accountDetailsReadPlatformService;
this.calendarReadPlatformService = calendarReadPlatformService; this.calendarReadPlatformService = calendarReadPlatformService;
this.meetingReadPlatformService = meetingReadPlatformService; this.meetingReadPlatformService = meetingReadPlatformService;
this.entityDatatableChecksReadService = entityDatatableChecksReadService;
} }
@GET @GET
@@ -134,6 +137,9 @@ public class CentersApiResource {
} }
final CenterData template = this.centerReadPlatformService.retrieveTemplate(officeId, staffInSelectedOfficeOnly); final CenterData template = this.centerReadPlatformService.retrieveTemplate(officeId, staffInSelectedOfficeOnly);
final List<DatatableData> datatableTemplates = this.entityDatatableChecksReadService
.retrieveTemplates(StatusEnum.CREATE.getCode().longValue(), EntityTables.GROUP.getName(), null);
template.setDatatables(datatableTemplates);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.centerApiJsonSerializer.serialize(settings, template, GroupingTypesApiConstants.CENTER_RESPONSE_DATA_PARAMETERS); return this.centerApiJsonSerializer.serialize(settings, template, GroupingTypesApiConstants.CENTER_RESPONSE_DATA_PARAMETERS);
@@ -87,13 +87,15 @@ public class GroupingTypesApiConstants {
// staff centres parameters // staff centres parameters
public static final String meetingFallCenters = "meetingFallCenters"; public static final String meetingFallCenters = "meetingFallCenters";
public static final String datatables = "datatables";
public static final Set<String> CENTER_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName, public static final Set<String> CENTER_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName,
dateFormatParamName, idParamName, nameParamName, externalIdParamName, officeIdParamName, staffIdParamName, activeParamName, dateFormatParamName, idParamName, nameParamName, externalIdParamName, officeIdParamName, staffIdParamName, activeParamName,
activationDateParamName, groupMembersParamName, submittedOnDateParamName)); activationDateParamName, groupMembersParamName, submittedOnDateParamName, datatables));
public static final Set<String> GROUP_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName, dateFormatParamName, public static final Set<String> GROUP_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName, dateFormatParamName,
idParamName, nameParamName, externalIdParamName, centerIdParamName, officeIdParamName, staffIdParamName, activeParamName, idParamName, nameParamName, externalIdParamName, centerIdParamName, officeIdParamName, staffIdParamName, activeParamName,
activationDateParamName, clientMembersParamName, collectionMeetingCalendar, submittedOnDateParamName)); activationDateParamName, clientMembersParamName, collectionMeetingCalendar, submittedOnDateParamName, datatables));
public static final Set<String> GROUP_ROLES_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(roleParamName, public static final Set<String> GROUP_ROLES_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(roleParamName,
clientIdParamName)); clientIdParamName));
@@ -106,16 +108,16 @@ public class GroupingTypesApiConstants {
public static final Set<String> CENTER_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName, nameParamName, public static final Set<String> CENTER_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName, nameParamName,
externalIdParamName, officeIdParamName, officeNameParamName, staffIdParamName, staffNameParamName, hierarchyParamName, externalIdParamName, officeIdParamName, officeNameParamName, staffIdParamName, staffNameParamName, hierarchyParamName,
officeOptionsParamName, staffOptionsParamName, statusParamName, activeParamName, activationDateParamName, timeLine, officeOptionsParamName, staffOptionsParamName, statusParamName, activeParamName, activationDateParamName, timeLine,
groupMembersParamName, collectionMeetingCalendar, closureReasons)); groupMembersParamName, collectionMeetingCalendar, closureReasons, datatables));
public static final Set<String> CENTER_GROUP_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName, nameParamName, public static final Set<String> CENTER_GROUP_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName, nameParamName,
externalIdParamName, officeIdParamName, officeNameParamName, staffIdParamName, staffNameParamName, hierarchyParamName, externalIdParamName, officeIdParamName, officeNameParamName, staffIdParamName, staffNameParamName, hierarchyParamName,
officeOptionsParamName, staffOptionsParamName, clientOptionsParamName)); officeOptionsParamName, staffOptionsParamName, clientOptionsParamName, datatables));
public static final Set<String> GROUP_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName, nameParamName, public static final Set<String> GROUP_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName, nameParamName,
externalIdParamName, officeIdParamName, officeNameParamName, "parentId", "parentName", staffIdParamName, staffNameParamName, externalIdParamName, officeIdParamName, officeNameParamName, "parentId", "parentName", staffIdParamName, staffNameParamName,
hierarchyParamName, officeOptionsParamName, statusParamName, activeParamName, activationDateParamName, staffOptionsParamName, hierarchyParamName, officeOptionsParamName, statusParamName, activeParamName, activationDateParamName, staffOptionsParamName,
clientOptionsParamName, timeLine)); clientOptionsParamName, timeLine, datatables));
public static final Set<String> ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName, public static final Set<String> ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName,
dateFormatParamName, activationDateParamName)); dateFormatParamName, activationDateParamName));
@@ -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.serialization.ToApiJsonSerializer;
import org.apache.fineract.infrastructure.core.service.Page; import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.SearchParameters; 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.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.portfolio.accountdetails.data.AccountSummaryCollectionData; import org.apache.fineract.portfolio.accountdetails.data.AccountSummaryCollectionData;
import org.apache.fineract.portfolio.accountdetails.service.AccountDetailsReadPlatformService; import org.apache.fineract.portfolio.accountdetails.service.AccountDetailsReadPlatformService;
@@ -99,6 +103,7 @@ public class GroupsApiResource {
private final AccountDetailsReadPlatformService accountDetailsReadPlatformService; private final AccountDetailsReadPlatformService accountDetailsReadPlatformService;
private final CalendarReadPlatformService calendarReadPlatformService; private final CalendarReadPlatformService calendarReadPlatformService;
private final MeetingReadPlatformService meetingReadPlatformService; private final MeetingReadPlatformService meetingReadPlatformService;
private final EntityDatatableChecksReadService entityDatatableChecksReadService;
@Autowired @Autowired
public GroupsApiResource(final PlatformSecurityContext context, final GroupReadPlatformService groupReadPlatformService, public GroupsApiResource(final PlatformSecurityContext context, final GroupReadPlatformService groupReadPlatformService,
@@ -111,7 +116,8 @@ public class GroupsApiResource {
final CollectionSheetReadPlatformService collectionSheetReadPlatformService, final FromJsonHelper fromJsonHelper, final CollectionSheetReadPlatformService collectionSheetReadPlatformService, final FromJsonHelper fromJsonHelper,
final GroupRolesReadPlatformService groupRolesReadPlatformService, final GroupRolesReadPlatformService groupRolesReadPlatformService,
final AccountDetailsReadPlatformService accountDetailsReadPlatformService, final AccountDetailsReadPlatformService accountDetailsReadPlatformService,
final CalendarReadPlatformService calendarReadPlatformService, final MeetingReadPlatformService meetingReadPlatformService) { final CalendarReadPlatformService calendarReadPlatformService, final MeetingReadPlatformService meetingReadPlatformService,
final EntityDatatableChecksReadService entityDatatableChecksReadService) {
this.context = context; this.context = context;
this.groupReadPlatformService = groupReadPlatformService; this.groupReadPlatformService = groupReadPlatformService;
@@ -128,6 +134,7 @@ public class GroupsApiResource {
this.accountDetailsReadPlatformService = accountDetailsReadPlatformService; this.accountDetailsReadPlatformService = accountDetailsReadPlatformService;
this.calendarReadPlatformService = calendarReadPlatformService; this.calendarReadPlatformService = calendarReadPlatformService;
this.meetingReadPlatformService = meetingReadPlatformService; this.meetingReadPlatformService = meetingReadPlatformService;
this.entityDatatableChecksReadService = entityDatatableChecksReadService;
} }
@GET @GET
@@ -148,8 +155,11 @@ public class GroupsApiResource {
GroupingTypesApiConstants.GROUP_RESPONSE_DATA_PARAMETERS); GroupingTypesApiConstants.GROUP_RESPONSE_DATA_PARAMETERS);
} }
final List<DatatableData> datatableTemplates = this.entityDatatableChecksReadService
.retrieveTemplates(StatusEnum.CREATE.getCode().longValue(), EntityTables.GROUP.getName(), null);
if (centerId != null) { if (centerId != null) {
final GroupGeneralData centerGroupTemplate = this.centerReadPlatformService.retrieveCenterGroupTemplate(centerId); final GroupGeneralData centerGroupTemplate = this.centerReadPlatformService.retrieveCenterGroupTemplate(centerId);
centerGroupTemplate.setDatatables(datatableTemplates);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.groupGeneralApiJsonSerializer.serialize(settings, centerGroupTemplate, return this.groupGeneralApiJsonSerializer.serialize(settings, centerGroupTemplate,
GroupingTypesApiConstants.CENTER_GROUP_RESPONSE_DATA_PARAMETERS); GroupingTypesApiConstants.CENTER_GROUP_RESPONSE_DATA_PARAMETERS);
@@ -157,6 +167,8 @@ public class GroupsApiResource {
final GroupGeneralData groupTemplate = this.groupReadPlatformService.retrieveTemplate(officeId, isCenterGroup, final GroupGeneralData groupTemplate = this.groupReadPlatformService.retrieveTemplate(officeId, isCenterGroup,
staffInSelectedOfficeOnly); staffInSelectedOfficeOnly);
groupTemplate.setDatatables(datatableTemplates);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.groupGeneralApiJsonSerializer.serialize(settings, groupTemplate, return this.groupGeneralApiJsonSerializer.serialize(settings, groupTemplate,
GroupingTypesApiConstants.GROUP_RESPONSE_DATA_PARAMETERS); GroupingTypesApiConstants.GROUP_RESPONSE_DATA_PARAMETERS);
@@ -20,9 +20,11 @@ package org.apache.fineract.portfolio.group.data;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import org.apache.fineract.infrastructure.codes.data.CodeValueData; import org.apache.fineract.infrastructure.codes.data.CodeValueData;
import org.apache.fineract.infrastructure.core.data.EnumOptionData; 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.office.data.OfficeData;
import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.organisation.staff.data.StaffData;
import org.apache.fineract.portfolio.calendar.data.CalendarData; import org.apache.fineract.portfolio.calendar.data.CalendarData;
@@ -63,6 +65,8 @@ public class CenterData {
private final BigDecimal totaldue; private final BigDecimal totaldue;
private final BigDecimal installmentDue; private final BigDecimal installmentDue;
private List<DatatableData> datatables = null;
public static CenterData template(final Long officeId, final String accountNo, final LocalDate activationDate, public static CenterData template(final Long officeId, final String accountNo, final LocalDate activationDate,
final Collection<OfficeData> officeOptions, final Collection<StaffData> staffOptions, final Collection<OfficeData> officeOptions, final Collection<StaffData> staffOptions,
final Collection<GroupGeneralData> groupMembersOptions, final BigDecimal totalCollected, final BigDecimal totalOverdue, final Collection<GroupGeneralData> groupMembersOptions, final BigDecimal totalCollected, final BigDecimal totalOverdue,
@@ -204,4 +208,8 @@ public class CenterData {
public String getStaffName() { public String getStaffName() {
return this.staffName; return this.staffName;
} }
public void setDatatables(final List<DatatableData> datatables) {
this.datatables = datatables;
}
} }
@@ -19,9 +19,11 @@
package org.apache.fineract.portfolio.group.data; package org.apache.fineract.portfolio.group.data;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import org.apache.fineract.infrastructure.codes.data.CodeValueData; import org.apache.fineract.infrastructure.codes.data.CodeValueData;
import org.apache.fineract.infrastructure.core.data.EnumOptionData; 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.office.data.OfficeData;
import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.organisation.staff.data.StaffData;
import org.apache.fineract.portfolio.calendar.data.CalendarData; import org.apache.fineract.portfolio.calendar.data.CalendarData;
@@ -70,6 +72,8 @@ public class GroupGeneralData {
private final Collection<CodeValueData> closureReasons; private final Collection<CodeValueData> closureReasons;
private final GroupTimelineData timeline; private final GroupTimelineData timeline;
private List<DatatableData> datatables = null;
public static GroupGeneralData lookup(final Long groupId, final String accountNo, final String groupName) { public static GroupGeneralData lookup(final Long groupId, final String accountNo, final String groupName) {
final Collection<ClientData> clientMembers = null; final Collection<ClientData> clientMembers = null;
final Collection<GroupRoleData> groupRoles = null; final Collection<GroupRoleData> groupRoles = null;
@@ -256,4 +260,8 @@ public class GroupGeneralData {
public Collection<ClientData> clientMembers() { public Collection<ClientData> clientMembers() {
return this.clientMembers; return this.clientMembers;
} }
public void setDatatables(final List<DatatableData> datatables) {
this.datatables = datatables;
}
} }
@@ -26,6 +26,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import com.google.gson.JsonArray;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.data.ApiParameterError;
@@ -116,6 +117,11 @@ public final class GroupingTypesDataValidator {
baseDataValidator.reset().parameter(GroupingTypesApiConstants.submittedOnDateParamName).value(submittedOnDate).notNull(); 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); throwExceptionIfValidationWarningsExist(dataValidationErrors);
} }
@@ -180,6 +186,11 @@ public final class GroupingTypesDataValidator {
baseDataValidator.reset().parameter(GroupingTypesApiConstants.submittedOnDateParamName).value(submittedOnDate).notNull(); 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); throwExceptionIfValidationWarningsExist(dataValidationErrors);
} }
@@ -240,6 +251,11 @@ public final class GroupingTypesDataValidator {
baseDataValidator.reset().parameter(GroupingTypesApiConstants.submittedOnDateParamName).value(submittedOnDate).notNull(); 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); throwExceptionIfValidationWarningsExist(dataValidationErrors);
} }
@@ -18,13 +18,7 @@
*/ */
package org.apache.fineract.portfolio.group.service; package org.apache.fineract.portfolio.group.service;
import java.util.Collection; import java.util.*;
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 javax.persistence.PersistenceException; 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.data.CommandProcessingResultBuilder;
import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException; import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; 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.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.office.domain.Office; import org.apache.fineract.organisation.office.domain.Office;
import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper; import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
import org.apache.fineract.organisation.office.exception.InvalidOfficeException; import org.apache.fineract.organisation.office.exception.InvalidOfficeException;
import org.apache.fineract.organisation.staff.domain.Staff; import org.apache.fineract.organisation.staff.domain.Staff;
import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper; 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.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.AccountNumberGenerator;
import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
import org.apache.fineract.portfolio.client.service.LoanStatusMapper; import org.apache.fineract.portfolio.client.service.LoanStatusMapper;
import org.apache.fineract.portfolio.group.api.GroupingTypesApiConstants; import org.apache.fineract.portfolio.group.api.GroupingTypesApiConstants;
import org.apache.fineract.portfolio.group.domain.Group; import org.apache.fineract.portfolio.group.domain.*;
import org.apache.fineract.portfolio.group.domain.GroupLevel; import org.apache.fineract.portfolio.group.exception.*;
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.serialization.GroupingTypesDataValidator; import org.apache.fineract.portfolio.group.serialization.GroupingTypesDataValidator;
import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
@@ -109,6 +94,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
private final SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper; private final SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper;
private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository; private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository;
private final AccountNumberGenerator accountNumberGenerator; private final AccountNumberGenerator accountNumberGenerator;
private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
@Autowired @Autowired
public GroupingTypesWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, public GroupingTypesWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -119,7 +105,8 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
final CodeValueRepositoryWrapper codeValueRepository, final CommandProcessingService commandProcessingService, final CodeValueRepositoryWrapper codeValueRepository, final CommandProcessingService commandProcessingService,
final CalendarInstanceRepository calendarInstanceRepository, final ConfigurationDomainService configurationDomainService, final CalendarInstanceRepository calendarInstanceRepository, final ConfigurationDomainService configurationDomainService,
final LoanRepositoryWrapper loanRepositoryWrapper, final LoanRepositoryWrapper loanRepositoryWrapper,
final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository, final AccountNumberGenerator accountNumberGenerator) { final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository, final AccountNumberGenerator accountNumberGenerator,
final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService) {
this.context = context; this.context = context;
this.groupRepository = groupRepository; this.groupRepository = groupRepository;
this.clientRepositoryWrapper = clientRepositoryWrapper; this.clientRepositoryWrapper = clientRepositoryWrapper;
@@ -136,6 +123,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
this.loanRepositoryWrapper = loanRepositoryWrapper; this.loanRepositoryWrapper = loanRepositoryWrapper;
this.accountNumberFormatRepository = accountNumberFormatRepository; this.accountNumberFormatRepository = accountNumberFormatRepository;
this.accountNumberGenerator = accountNumberGenerator; this.accountNumberGenerator = accountNumberGenerator;
this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService;
} }
private CommandProcessingResult createGroupingType(final JsonCommand command, final GroupTypes groupingType, final Long centerId) { 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); this.groupRepository.saveAndFlush(newGroup);
newGroup.captureStaffHistoryDuringCenterCreation(staff, activationDate); 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() // return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) // .withCommandId(command.commandId()) //
.withOfficeId(groupOffice.getId()) // .withOfficeId(groupOffice.getId()) //
@@ -296,6 +294,10 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
final LocalDate activationDate = command.localDateValueOfParameterNamed("activationDate"); final LocalDate activationDate = command.localDateValueOfParameterNamed("activationDate");
validateOfficeOpeningDateisAfterGroupOrCenterOpeningDate(group.getOffice(), group.getGroupLevel(), activationDate); validateOfficeOpeningDateisAfterGroupOrCenterOpeningDate(group.getOffice(), group.getGroupLevel(), activationDate);
entityDatatableChecksWritePlatformService.runTheCheck(groupId, EntityTables.GROUP.getName(),
StatusEnum.ACTIVATE.getCode().longValue(), EntityTables.GROUP.getForeignKeyColumnNameOnDatatable());
group.activate(currentUser, activationDate); group.activate(currentUser, activationDate);
this.groupRepository.saveAndFlush(group); this.groupRepository.saveAndFlush(group);
@@ -585,6 +587,9 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
validateLoansAndSavingsForGroupOrCenterClose(group, closureDate); validateLoansAndSavingsForGroupOrCenterClose(group, closureDate);
entityDatatableChecksWritePlatformService.runTheCheck(groupId, EntityTables.GROUP.getName(),
StatusEnum.CLOSE.getCode().longValue(),EntityTables.GROUP.getForeignKeyColumnNameOnDatatable());
group.close(currentUser, closureReason, closureDate); group.close(currentUser, closureReason, closureDate);
this.groupRepository.saveAndFlush(group); this.groupRepository.saveAndFlush(group);
@@ -657,6 +662,10 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
validateLoansAndSavingsForGroupOrCenterClose(center, closureDate); validateLoansAndSavingsForGroupOrCenterClose(center, closureDate);
entityDatatableChecksWritePlatformService.runTheCheck(centerId, EntityTables.GROUP.getName(),
StatusEnum.ACTIVATE.getCode().longValue(), EntityTables.GROUP.getForeignKeyColumnNameOnDatatable());
center.close(currentUser, closureReason, closureDate); center.close(currentUser, closureReason, closureDate);
this.groupRepository.saveAndFlush(center); this.groupRepository.saveAndFlush(center);
@@ -123,4 +123,5 @@ public interface LoanApiConstants {
public static final String loanIdToClose = "loanIdToClose"; public static final String loanIdToClose = "loanIdToClose";
public static final String topupAmount = "topupAmount"; public static final String topupAmount = "topupAmount";
public static final String datatables = "datatables";
} }
@@ -20,12 +20,7 @@ package org.apache.fineract.portfolio.loanaccount.api;
import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.interestType; import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.interestType;
import java.util.Arrays; import java.util.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; 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.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.Page; import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.SearchParameters; 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.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.organisation.staff.data.StaffData;
@@ -139,7 +138,8 @@ public class LoansApiResource {
"loanOfficerOptions", "loanPurposeOptions", "loanCollateralOptions", "chargeTemplate", "calendarOptions", "loanOfficerOptions", "loanPurposeOptions", "loanCollateralOptions", "chargeTemplate", "calendarOptions",
"syncDisbursementWithMeeting", "loanCounter", "loanProductCounter", "notes", "accountLinkingOptions", "linkedAccount", "syncDisbursementWithMeeting", "loanCounter", "loanProductCounter", "notes", "accountLinkingOptions", "linkedAccount",
"interestRateDifferential", "isFloatingInterestRate", "interestRatesPeriods", LoanApiConstants.canUseForTopup, "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<String> LOAN_APPROVAL_DATA_PARAMETERS = new HashSet<>(Arrays.asList("approvalDate", "approvalAmount")); private final Set<String> LOAN_APPROVAL_DATA_PARAMETERS = new HashSet<>(Arrays.asList("approvalDate", "approvalAmount"));
private final String resourceNameForPermissions = "LOAN"; private final String resourceNameForPermissions = "LOAN";
@@ -168,6 +168,7 @@ public class LoansApiResource {
private final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService; private final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService;
private final LoanScheduleHistoryReadPlatformService loanScheduleHistoryReadPlatformService; private final LoanScheduleHistoryReadPlatformService loanScheduleHistoryReadPlatformService;
private final AccountDetailsReadPlatformService accountDetailsReadPlatformService; private final AccountDetailsReadPlatformService accountDetailsReadPlatformService;
private final EntityDatatableChecksReadService entityDatatableChecksReadService;
@Autowired @Autowired
public LoansApiResource(final PlatformSecurityContext context, final LoanReadPlatformService loanReadPlatformService, public LoansApiResource(final PlatformSecurityContext context, final LoanReadPlatformService loanReadPlatformService,
@@ -187,7 +188,8 @@ public class LoansApiResource {
final PortfolioAccountReadPlatformService portfolioAccountReadPlatformServiceImpl, final PortfolioAccountReadPlatformService portfolioAccountReadPlatformServiceImpl,
final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService, final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService,
final LoanScheduleHistoryReadPlatformService loanScheduleHistoryReadPlatformService, final LoanScheduleHistoryReadPlatformService loanScheduleHistoryReadPlatformService,
final AccountDetailsReadPlatformService accountDetailsReadPlatformService) { final AccountDetailsReadPlatformService accountDetailsReadPlatformService,
final EntityDatatableChecksReadService entityDatatableChecksReadService) {
this.context = context; this.context = context;
this.loanReadPlatformService = loanReadPlatformService; this.loanReadPlatformService = loanReadPlatformService;
this.loanProductReadPlatformService = loanProductReadPlatformService; this.loanProductReadPlatformService = loanProductReadPlatformService;
@@ -212,6 +214,7 @@ public class LoansApiResource {
this.accountAssociationsReadPlatformService = accountAssociationsReadPlatformService; this.accountAssociationsReadPlatformService = accountAssociationsReadPlatformService;
this.loanScheduleHistoryReadPlatformService = loanScheduleHistoryReadPlatformService; this.loanScheduleHistoryReadPlatformService = loanScheduleHistoryReadPlatformService;
this.accountDetailsReadPlatformService = accountDetailsReadPlatformService; this.accountDetailsReadPlatformService = accountDetailsReadPlatformService;
this.entityDatatableChecksReadService = entityDatatableChecksReadService;
} }
/* /*
@@ -347,6 +350,10 @@ public class LoansApiResource {
newLoanAccount = LoanAccountData.associationsAndTemplate(newLoanAccount, productOptions, allowedLoanOfficers, calendarOptions, newLoanAccount = LoanAccountData.associationsAndTemplate(newLoanAccount, productOptions, allowedLoanOfficers, calendarOptions,
accountLinkingOptions); accountLinkingOptions);
} }
final List<DatatableData> datatableTemplates = this.entityDatatableChecksReadService
.retrieveTemplates(StatusEnum.CREATE.getCode().longValue(), EntityTables.LOAN.getName(), productId);
newLoanAccount.setDatatables(datatableTemplates);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, newLoanAccount, this.LOAN_DATA_PARAMETERS); return this.toApiJsonSerializer.serialize(settings, newLoanAccount, this.LOAN_DATA_PARAMETERS);
} }
@@ -19,15 +19,13 @@
package org.apache.fineract.portfolio.loanaccount.data; package org.apache.fineract.portfolio.loanaccount.data;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.Transient; import javax.persistence.Transient;
import org.apache.fineract.infrastructure.codes.data.CodeValueData; import org.apache.fineract.infrastructure.codes.data.CodeValueData;
import org.apache.fineract.infrastructure.core.data.EnumOptionData; 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.monetary.data.CurrencyData;
import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.organisation.staff.data.StaffData;
import org.apache.fineract.portfolio.account.data.PortfolioAccountData; import org.apache.fineract.portfolio.account.data.PortfolioAccountData;
@@ -214,6 +212,8 @@ public class LoanAccountData {
private final Integer minimumGap; private final Integer minimumGap;
private final Integer maximumGap; private final Integer maximumGap;
private List<DatatableData> datatables = null;
/** /**
* Used to produce a {@link LoanAccountData} with only collateral options * Used to produce a {@link LoanAccountData} with only collateral options
* for now. * for now.
@@ -1618,4 +1618,8 @@ public class LoanAccountData {
public BigDecimal getInterestRateDifferential() { public BigDecimal getInterestRateDifferential() {
return this.interestRateDifferential; return this.interestRateDifferential;
} }
public void setDatatables(final List<DatatableData> datatables) {
this.datatables = datatables;
}
} }
@@ -37,6 +37,7 @@ import org.apache.fineract.infrastructure.core.exception.UnsupportedParameterExc
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.portfolio.accountdetails.domain.AccountType; import org.apache.fineract.portfolio.accountdetails.domain.AccountType;
import org.apache.fineract.portfolio.calendar.service.CalendarUtils; 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.api.LoanApiConstants;
import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge; import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
@@ -92,7 +93,7 @@ public final class LoanApplicationCommandFromApiJsonHelper {
LoanApiConstants.linkAccountIdParameterName, LoanApiConstants.disbursementDataParameterName, LoanApiConstants.linkAccountIdParameterName, LoanApiConstants.disbursementDataParameterName,
LoanApiConstants.emiAmountParameterName, LoanApiConstants.maxOutstandingBalanceParameterName, LoanApiConstants.emiAmountParameterName, LoanApiConstants.maxOutstandingBalanceParameterName,
LoanProductConstants.graceOnArrearsAgeingParameterName, LoanApiConstants.createStandingInstructionAtDisbursementParameterName, LoanProductConstants.graceOnArrearsAgeingParameterName, LoanApiConstants.createStandingInstructionAtDisbursementParameterName,
LoanApiConstants.isTopup, LoanApiConstants.loanIdToClose)); LoanApiConstants.isTopup, LoanApiConstants.loanIdToClose, LoanApiConstants.datatables));
private final FromJsonHelper fromApiJsonHelper; private final FromJsonHelper fromApiJsonHelper;
private final CalculateLoanScheduleQueryFromApiJsonHelper apiJsonHelper; 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); validateLoanMultiDisbursementdate(element, baseDataValidator, expectedDisbursementDate, principal);
validatePartialPeriodSupport(interestCalculationPeriodType, baseDataValidator, element, loanProduct); validatePartialPeriodSupport(interestCalculationPeriodType, baseDataValidator, element, loanProduct);
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
@@ -19,14 +19,8 @@
package org.apache.fineract.portfolio.loanaccount.service; package org.apache.fineract.portfolio.loanaccount.service;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.EntityExistsException;
import javax.persistence.PersistenceException; import javax.persistence.PersistenceException;
import org.apache.commons.lang.StringUtils; 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.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; 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.FineractEntityAccessConstants;
import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityAccessType; import org.apache.fineract.infrastructure.entityaccess.domain.*;
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.exception.NotOfficeSpecificProductException; import org.apache.fineract.infrastructure.entityaccess.exception.NotOfficeSpecificProductException;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.staff.domain.Staff; 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.AccountAssociations;
import org.apache.fineract.portfolio.account.domain.AccountAssociationsRepository; import org.apache.fineract.portfolio.account.domain.AccountAssociationsRepository;
import org.apache.fineract.portfolio.accountdetails.domain.AccountType; 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.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.exception.CalendarNotFoundException;
import org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformService; import org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformService;
import org.apache.fineract.portfolio.charge.domain.Charge; 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.api.LoanApiConstants;
import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData; import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO; import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
import org.apache.fineract.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine; import org.apache.fineract.portfolio.loanaccount.domain.*;
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.exception.LoanApplicationDateException; import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationDateException;
import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeDeleted; import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeDeleted;
import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified; 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.LoanApplicationCommandFromApiJsonHelper;
import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationTransitionApiJsonValidator; import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationTransitionApiJsonValidator;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants; import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; import org.apache.fineract.portfolio.loanproduct.domain.*;
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.exception.LinkedAccountRequiredException; import org.apache.fineract.portfolio.loanproduct.exception.LinkedAccountRequiredException;
import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException; import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException;
import org.apache.fineract.portfolio.loanproduct.serialization.LoanProductDataValidator; import org.apache.fineract.portfolio.loanproduct.serialization.LoanProductDataValidator;
@@ -170,6 +143,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
private final LoanScheduleAssembler loanScheduleAssembler; private final LoanScheduleAssembler loanScheduleAssembler;
private final LoanUtilService loanUtilService; private final LoanUtilService loanUtilService;
private final CalendarReadPlatformService calendarReadPlatformService; private final CalendarReadPlatformService calendarReadPlatformService;
private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
private final GlobalConfigurationRepositoryWrapper globalConfigurationRepository; private final GlobalConfigurationRepositoryWrapper globalConfigurationRepository;
private final FineractEntityToEntityMappingRepository repository; private final FineractEntityToEntityMappingRepository repository;
private final FineractEntityRelationRepository fineractEntityRelationRepository; private final FineractEntityRelationRepository fineractEntityRelationRepository;
@@ -194,7 +168,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
final BusinessEventNotifierService businessEventNotifierService, final ConfigurationDomainService configurationDomainService, final BusinessEventNotifierService businessEventNotifierService, final ConfigurationDomainService configurationDomainService,
final LoanScheduleAssembler loanScheduleAssembler, final LoanUtilService loanUtilService, final LoanScheduleAssembler loanScheduleAssembler, final LoanUtilService loanUtilService,
final CalendarReadPlatformService calendarReadPlatformService, final GlobalConfigurationRepositoryWrapper globalConfigurationRepository, 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.context = context;
this.fromJsonHelper = fromJsonHelper; this.fromJsonHelper = fromJsonHelper;
this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator; this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator;
@@ -225,6 +200,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
this.loanScheduleAssembler = loanScheduleAssembler; this.loanScheduleAssembler = loanScheduleAssembler;
this.loanUtilService = loanUtilService; this.loanUtilService = loanUtilService;
this.calendarReadPlatformService = calendarReadPlatformService; this.calendarReadPlatformService = calendarReadPlatformService;
this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService;
this.globalConfigurationRepository = globalConfigurationRepository; this.globalConfigurationRepository = globalConfigurationRepository;
this.repository = repository; this.repository = repository;
this.fineractEntityRelationRepository = fineractEntityRelationRepository; this.fineractEntityRelationRepository = fineractEntityRelationRepository;
@@ -408,6 +384,17 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
this.accountAssociationsRepository.save(accountAssociations); 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() // return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) // .withCommandId(command.commandId()) //
.withEntityId(newLoanApplication.getId()) // .withEntityId(newLoanApplication.getId()) //
@@ -1107,6 +1094,9 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
final Map<String, Object> changes = loan.loanApplicationApproval(currentUser, command, disbursementDataArray, final Map<String, Object> changes = loan.loanApplicationApproval(currentUser, command, disbursementDataArray,
defaultLoanLifecycleStateMachine()); defaultLoanLifecycleStateMachine());
entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(),
StatusEnum.APPROVE.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId());
if (!changes.isEmpty()) { if (!changes.isEmpty()) {
// If loan approved amount less than loan demanded amount, then need // 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()); this.loanApplicationTransitionApiJsonValidator.validateRejection(command.json());
final Loan loan = retrieveLoanBy(loanId); final Loan loan = retrieveLoanBy(loanId);
checkClientOrGroupActive(loan); checkClientOrGroupActive(loan);
entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(),
StatusEnum.REJECTED.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(),loan.productId());
final Map<String, Object> changes = loan.loanApplicationRejection(currentUser, command, defaultLoanLifecycleStateMachine()); final Map<String, Object> changes = loan.loanApplicationRejection(currentUser, command, defaultLoanLifecycleStateMachine());
if (!changes.isEmpty()) { if (!changes.isEmpty()) {
this.loanRepositoryWrapper.save(loan); this.loanRepositoryWrapper.save(loan);
@@ -1256,6 +1250,9 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
final Loan loan = retrieveLoanBy(loanId); final Loan loan = retrieveLoanBy(loanId);
checkClientOrGroupActive(loan); checkClientOrGroupActive(loan);
entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(),
StatusEnum.WITHDRAWN.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId());
final Map<String, Object> changes = loan.loanApplicationWithdrawnByApplicant(currentUser, command, final Map<String, Object> changes = loan.loanApplicationWithdrawnByApplicant(currentUser, command,
defaultLoanLifecycleStateMachine()); defaultLoanLifecycleStateMachine());
if (!changes.isEmpty()) { if (!changes.isEmpty()) {
@@ -19,17 +19,7 @@
package org.apache.fineract.portfolio.loanaccount.service; package org.apache.fineract.portfolio.loanaccount.service;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.*;
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 org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService; 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.exception.PlatformServiceUnavailableException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.DateUtils; 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.annotation.CronTarget;
import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException; import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
import org.apache.fineract.infrastructure.jobs.service.JobName; 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.PortfolioAccountType;
import org.apache.fineract.portfolio.account.data.AccountTransferDTO; import org.apache.fineract.portfolio.account.data.AccountTransferDTO;
import org.apache.fineract.portfolio.account.data.PortfolioAccountData; import org.apache.fineract.portfolio.account.data.PortfolioAccountData;
import org.apache.fineract.portfolio.account.domain.AccountAssociationType; import org.apache.fineract.portfolio.account.domain.*;
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.service.AccountAssociationsReadPlatformService; import org.apache.fineract.portfolio.account.service.AccountAssociationsReadPlatformService;
import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService; import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
import org.apache.fineract.portfolio.account.service.AccountTransfersWritePlatformService; import org.apache.fineract.portfolio.account.service.AccountTransfersWritePlatformService;
import org.apache.fineract.portfolio.accountdetails.domain.AccountType; 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.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.calendar.exception.CalendarParameterUpdateNotSupportedException;
import org.apache.fineract.portfolio.charge.domain.Charge; import org.apache.fineract.portfolio.charge.domain.Charge;
import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode; import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode;
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper; import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
import org.apache.fineract.portfolio.charge.exception.ChargeCannotBeUpdatedException; import org.apache.fineract.portfolio.charge.exception.*;
import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeAddedException;
import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeDeletedException;
import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeDeletedException.LOAN_CHARGE_CANNOT_BE_DELETED_REASON; 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.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.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.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.domain.Client;
import org.apache.fineract.portfolio.client.exception.ClientNotActiveException; import org.apache.fineract.portfolio.client.exception.ClientNotActiveException;
import org.apache.fineract.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand; 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.group.exception.GroupNotActiveException;
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants; import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
import org.apache.fineract.portfolio.loanaccount.command.LoanUpdateCommand; import org.apache.fineract.portfolio.loanaccount.command.LoanUpdateCommand;
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO; import org.apache.fineract.portfolio.loanaccount.data.*;
import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData; import org.apache.fineract.portfolio.loanaccount.domain.*;
import org.apache.fineract.portfolio.loanaccount.data.LoanChargePaidByData; import org.apache.fineract.portfolio.loanaccount.exception.*;
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.guarantor.service.GuarantorDomainService; 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.data.OverdueLoanScheduleData;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator;
@@ -231,6 +167,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final GuarantorDomainService guarantorDomainService; private final GuarantorDomainService guarantorDomainService;
private final LoanUtilService loanUtilService; private final LoanUtilService loanUtilService;
private final LoanSummaryWrapper loanSummaryWrapper; private final LoanSummaryWrapper loanSummaryWrapper;
private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy; private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy;
private final CodeValueRepositoryWrapper codeValueRepository; private final CodeValueRepositoryWrapper codeValueRepository;
@@ -260,6 +197,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final AccountTransferDetailRepository accountTransferDetailRepository, final AccountTransferDetailRepository accountTransferDetailRepository,
final BusinessEventNotifierService businessEventNotifierService, final GuarantorDomainService guarantorDomainService, final BusinessEventNotifierService businessEventNotifierService, final GuarantorDomainService guarantorDomainService,
final LoanUtilService loanUtilService, final LoanSummaryWrapper loanSummaryWrapper, final LoanUtilService loanUtilService, final LoanSummaryWrapper loanSummaryWrapper,
final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService,
final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy, final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy,
final CodeValueRepositoryWrapper codeValueRepository, final CodeValueRepositoryWrapper codeValueRepository,
final LoanRepositoryWrapper loanRepositoryWrapper) { final LoanRepositoryWrapper loanRepositoryWrapper) {
@@ -299,6 +237,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.loanUtilService = loanUtilService; this.loanUtilService = loanUtilService;
this.loanSummaryWrapper = loanSummaryWrapper; this.loanSummaryWrapper = loanSummaryWrapper;
this.transactionProcessingStrategy = transactionProcessingStrategy; this.transactionProcessingStrategy = transactionProcessingStrategy;
this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService;
this.codeValueRepository = codeValueRepository; this.codeValueRepository = codeValueRepository;
} }
@@ -318,7 +257,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final Loan loan = this.loanAssembler.assembleFrom(loanId); final Loan loan = this.loanAssembler.assembleFrom(loanId);
final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate"); final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate");
// validate ActualDisbursement Date Against Expected Disbursement Date // validate ActualDisbursement Date Against Expected Disbursement Date
LoanProduct loanProduct = loan.loanProduct(); LoanProduct loanProduct = loan.loanProduct();
if(loanProduct.syncExpectedWithDisbursementDate()){ if(loanProduct.syncExpectedWithDisbursementDate()){
@@ -329,6 +267,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LocalDate nextPossibleRepaymentDate = loan.getNextPossibleRepaymentDateForRescheduling(); final LocalDate nextPossibleRepaymentDate = loan.getNextPossibleRepaymentDateForRescheduling();
final Date rescheduledRepaymentDate = command.DateValueOfParameterNamed("adjustRepaymentDate"); 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 // check for product mix validations
checkForProductMixRestrictions(loan); checkForProductMixRestrictions(loan);
@@ -1114,6 +1055,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
checkClientOrGroupActive(loan); checkClientOrGroupActive(loan);
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.LOAN_WRITTEN_OFF, this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.LOAN_WRITTEN_OFF,
constructEntityMap(BUSINESS_ENTITY.LOAN, loan)); constructEntityMap(BUSINESS_ENTITY.LOAN, loan));
entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(),
StatusEnum.WRITE_OFF.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId());
removeLoanCycle(loan); removeLoanCycle(loan);
final List<Long> existingTransactionIds = new ArrayList<>(); final List<Long> existingTransactionIds = new ArrayList<>();
@@ -167,6 +167,8 @@ public class SavingsApiConstants {
public static final String daysToInactiveParamName = "daysToInactive"; public static final String daysToInactiveParamName = "daysToInactive";
public static final String daysToDormancyParamName = "daysToDormancy"; public static final String daysToDormancyParamName = "daysToDormancy";
public static final String daysToEscheatParamName = "daysToEscheat"; public static final String daysToEscheatParamName = "daysToEscheat";
public static final String datatables = "datatables";
public static final Set<String> SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName, public static final Set<String> SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName,
@@ -220,7 +222,7 @@ public class SavingsApiConstants {
// withdrawalFeeAmountParamName, withdrawalFeeTypeParamName, // withdrawalFeeAmountParamName, withdrawalFeeTypeParamName,
withdrawalFeeForTransfersParamName, feeAmountParamName, feeOnMonthDayParamName, chargesParamName, allowOverdraftParamName, withdrawalFeeForTransfersParamName, feeAmountParamName, feeOnMonthDayParamName, chargesParamName, allowOverdraftParamName,
overdraftLimitParamName, minRequiredBalanceParamName, enforceMinRequiredBalanceParamName, overdraftLimitParamName, minRequiredBalanceParamName, enforceMinRequiredBalanceParamName,
nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName, withHoldTaxParamName)); nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName, withHoldTaxParamName,datatables));
/** /**
* These parameters will match the class level parameters of * These parameters will match the class level parameters of
@@ -236,7 +238,7 @@ public class SavingsApiConstants {
feeOnMonthDayParamName, "summary", "transactions", "productOptions", "interestCompoundingPeriodTypeOptions", feeOnMonthDayParamName, "summary", "transactions", "productOptions", "interestCompoundingPeriodTypeOptions",
"interestPostingPeriodTypeOptions", "interestCalculationTypeOptions", "interestCalculationDaysInYearTypeOptions", "interestPostingPeriodTypeOptions", "interestCalculationTypeOptions", "interestCalculationDaysInYearTypeOptions",
"lockinPeriodFrequencyTypeOptions", "withdrawalFeeTypeOptions", "withdrawalFee", "annualFee", onHoldFundsParamName, "lockinPeriodFrequencyTypeOptions", "withdrawalFeeTypeOptions", "withdrawalFee", "annualFee", onHoldFundsParamName,
nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName)); nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName, datatables));
public static final Set<String> SAVINGS_ACCOUNT_TRANSACTION_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName, public static final Set<String> SAVINGS_ACCOUNT_TRANSACTION_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName,
dateFormatParamName, transactionDateParamName, transactionAmountParamName, paymentTypeIdParamName, dateFormatParamName, transactionDateParamName, transactionAmountParamName, paymentTypeIdParamName,
@@ -21,10 +21,12 @@ package org.apache.fineract.portfolio.savings.data;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.fineract.infrastructure.core.data.EnumOptionData; 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.monetary.data.CurrencyData;
import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.organisation.staff.data.StaffData;
import org.apache.fineract.portfolio.charge.data.ChargeData; import org.apache.fineract.portfolio.charge.data.ChargeData;
@@ -100,6 +102,8 @@ public class SavingsAccountData {
private final BigDecimal nominalAnnualInterestRateOverdraft; private final BigDecimal nominalAnnualInterestRateOverdraft;
private final BigDecimal minOverdraftForInterestCalculation; private final BigDecimal minOverdraftForInterestCalculation;
private List<DatatableData> datatables = null;
public static SavingsAccountData instance(final Long id, final String accountNo, final EnumOptionData depositType, 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 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, final Long productId, final String productName, final Long fieldOfficerId, final String fieldOfficerName,
@@ -557,4 +561,8 @@ public class SavingsAccountData {
public Collection<SavingsAccountChargeData> charges() { public Collection<SavingsAccountChargeData> charges() {
return (this.charges == null) ? new HashSet<SavingsAccountChargeData>() : this.charges; return (this.charges == null) ? new HashSet<SavingsAccountChargeData>() : this.charges;
} }
public void setDatatables(final List<DatatableData> datatables) {
this.datatables = datatables;
}
} }
@@ -212,6 +212,11 @@ public class SavingsAccountDataValidator {
baseDataValidator.reset().parameter(withHoldTaxParamName).value(withHoldTax).ignoreIfNull().validateForBooleanValue(); 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); validateSavingsCharges(element, baseDataValidator);
validateOverdraftParams(baseDataValidator, element); validateOverdraftParams(baseDataValidator, element);
@@ -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.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource; import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
import org.apache.fineract.infrastructure.core.service.SearchParameters; 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.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.organisation.monetary.domain.Money; import org.apache.fineract.organisation.monetary.domain.Money;
@@ -102,12 +106,15 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
// pagination // pagination
private final PaginationHelper<SavingsAccountData> paginationHelper = new PaginationHelper<>(); private final PaginationHelper<SavingsAccountData> paginationHelper = new PaginationHelper<>();
private final EntityDatatableChecksReadService entityDatatableChecksReadService;
@Autowired @Autowired
public SavingsAccountReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource, public SavingsAccountReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
final ClientReadPlatformService clientReadPlatformService, final GroupReadPlatformService groupReadPlatformService, final ClientReadPlatformService clientReadPlatformService, final GroupReadPlatformService groupReadPlatformService,
final SavingsProductReadPlatformService savingProductReadPlatformService, final SavingsProductReadPlatformService savingProductReadPlatformService,
final StaffReadPlatformService staffReadPlatformService, final SavingsDropdownReadPlatformService dropdownReadPlatformService, final StaffReadPlatformService staffReadPlatformService, final SavingsDropdownReadPlatformService dropdownReadPlatformService,
final ChargeReadPlatformService chargeReadPlatformService) { final ChargeReadPlatformService chargeReadPlatformService,
final EntityDatatableChecksReadService entityDatatableChecksReadService) {
this.context = context; this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource); this.jdbcTemplate = new JdbcTemplate(dataSource);
this.clientReadPlatformService = clientReadPlatformService; this.clientReadPlatformService = clientReadPlatformService;
@@ -120,6 +127,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
this.savingAccountMapper = new SavingAccountMapper(); this.savingAccountMapper = new SavingAccountMapper();
// this.annualFeeMapper = new SavingsAccountAnnualFeeMapper(); // this.annualFeeMapper = new SavingsAccountAnnualFeeMapper();
this.chargeReadPlatformService = chargeReadPlatformService; this.chargeReadPlatformService = chargeReadPlatformService;
this.entityDatatableChecksReadService = entityDatatableChecksReadService;
} }
@Override @Override
@@ -687,6 +695,10 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
charges, chargeOptions); charges, chargeOptions);
} }
final List<DatatableData> datatableTemplates = this.entityDatatableChecksReadService
.retrieveTemplates(StatusEnum.CREATE.getCode().longValue(), EntityTables.SAVING.getName(), productId);
template.setDatatables(datatableTemplates);
return template; return template;
} }
@@ -18,25 +18,11 @@
*/ */
package org.apache.fineract.portfolio.savings.service; 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.*;
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 java.math.BigDecimal; import java.math.BigDecimal;
import java.math.MathContext; import java.math.MathContext;
import java.util.ArrayList; import java.util.*;
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 org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService; 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.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavailableException; import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavailableException;
import org.apache.fineract.infrastructure.core.service.DateUtils; 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.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.holiday.domain.HolidayRepositoryWrapper; import org.apache.fineract.organisation.holiday.domain.HolidayRepositoryWrapper;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; import org.apache.fineract.organisation.monetary.domain.*;
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.office.domain.Office; import org.apache.fineract.organisation.office.domain.Office;
import org.apache.fineract.organisation.staff.domain.Staff; import org.apache.fineract.organisation.staff.domain.Staff;
import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper; 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.SavingsAccountDataValidator;
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionDTO; import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionDTO;
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionDataValidator; import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionDataValidator;
import org.apache.fineract.portfolio.savings.domain.DepositAccountOnHoldTransaction; import org.apache.fineract.portfolio.savings.domain.*;
import org.apache.fineract.portfolio.savings.domain.DepositAccountOnHoldTransactionRepository; import org.apache.fineract.portfolio.savings.exception.*;
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.exception.PostInterestAsOnDateException.PostInterestAsOnException_TYPE; 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.AppUser;
import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper; import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
@@ -140,6 +109,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
private final WorkingDaysRepositoryWrapper workingDaysRepository; private final WorkingDaysRepositoryWrapper workingDaysRepository;
private final ConfigurationDomainService configurationDomainService; private final ConfigurationDomainService configurationDomainService;
private final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository; private final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository;
private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
private final AppUserRepositoryWrapper appuserRepository; private final AppUserRepositoryWrapper appuserRepository;
private final StandingInstructionRepository standingInstructionRepository; private final StandingInstructionRepository standingInstructionRepository;
private final BusinessEventNotifierService businessEventNotifierService; private final BusinessEventNotifierService businessEventNotifierService;
@@ -162,6 +132,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final SavingsAccountDataValidator fromApiJsonDeserializer, final SavingsAccountDataValidator fromApiJsonDeserializer,
final StaffRepositoryWrapper staffRepository, final ConfigurationDomainService configurationDomainService, final StaffRepositoryWrapper staffRepository, final ConfigurationDomainService configurationDomainService,
final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository, final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository,
final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService,
final AppUserRepositoryWrapper appuserRepository, final AppUserRepositoryWrapper appuserRepository,
final StandingInstructionRepository standingInstructionRepository, final StandingInstructionRepository standingInstructionRepository,
final BusinessEventNotifierService businessEventNotifierService) { final BusinessEventNotifierService businessEventNotifierService) {
@@ -186,6 +157,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
this.staffRepository = staffRepository; this.staffRepository = staffRepository;
this.configurationDomainService = configurationDomainService; this.configurationDomainService = configurationDomainService;
this.depositAccountOnHoldTransactionRepository = depositAccountOnHoldTransactionRepository; this.depositAccountOnHoldTransactionRepository = depositAccountOnHoldTransactionRepository;
this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService;
this.appuserRepository = appuserRepository; this.appuserRepository = appuserRepository;
this.standingInstructionRepository = standingInstructionRepository; this.standingInstructionRepository = standingInstructionRepository;
this.businessEventNotifierService = businessEventNotifierService; this.businessEventNotifierService = businessEventNotifierService;
@@ -205,6 +177,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final Set<Long> existingReversedTransactionIds = new HashSet<>(); final Set<Long> existingReversedTransactionIds = new HashSet<>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
final Map<String, Object> changes = account.activate(user, command, DateUtils.getLocalDateOfTenant()); final Map<String, Object> 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()) { if (!changes.isEmpty()) {
final Locale locale = command.extractLocale(); final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); 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"; + " is not allowed, since it is linked with one of the active accounts";
throw new SavingsAccountClosingNotAllowedException("linked", defaultUserMessage, savingsId); 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); final boolean isWithdrawBalance = command.booleanPrimitiveValueOfParameterNamed(withdrawBalanceParamName);
@@ -20,13 +20,7 @@ package org.apache.fineract.portfolio.savings.service;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
import java.util.ArrayList; import java.util.*;
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 javax.persistence.PersistenceException; 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.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.service.DateUtils; 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.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.monetary.domain.Money; import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.organisation.staff.domain.Staff; 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.SavingsApiConstants;
import org.apache.fineract.portfolio.savings.data.SavingsAccountDataDTO; import org.apache.fineract.portfolio.savings.data.SavingsAccountDataDTO;
import org.apache.fineract.portfolio.savings.data.SavingsAccountDataValidator; import org.apache.fineract.portfolio.savings.data.SavingsAccountDataValidator;
import org.apache.fineract.portfolio.savings.domain.SavingsAccount; import org.apache.fineract.portfolio.savings.domain.*;
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.exception.SavingsProductNotFoundException; import org.apache.fineract.portfolio.savings.exception.SavingsProductNotFoundException;
import org.apache.fineract.useradministration.domain.AppUser; import org.apache.fineract.useradministration.domain.AppUser;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -106,7 +96,8 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
private final SavingsAccountWritePlatformService savingsAccountWritePlatformService; private final SavingsAccountWritePlatformService savingsAccountWritePlatformService;
private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository; private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository;
private final BusinessEventNotifierService businessEventNotifierService; private final BusinessEventNotifierService businessEventNotifierService;
private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
@Autowired @Autowired
public SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, public SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
final SavingsAccountRepositoryWrapper savingAccountRepository, final SavingsAccountAssembler savingAccountAssembler, final SavingsAccountRepositoryWrapper savingAccountRepository, final SavingsAccountAssembler savingAccountAssembler,
@@ -119,7 +110,8 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
final SavingsAccountDomainService savingsAccountDomainService, final SavingsAccountDomainService savingsAccountDomainService,
final SavingsAccountWritePlatformService savingsAccountWritePlatformService, final SavingsAccountWritePlatformService savingsAccountWritePlatformService,
final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository, final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository,
final BusinessEventNotifierService businessEventNotifierService) { final BusinessEventNotifierService businessEventNotifierService,
final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService) {
this.context = context; this.context = context;
this.savingAccountRepository = savingAccountRepository; this.savingAccountRepository = savingAccountRepository;
this.savingAccountAssembler = savingAccountAssembler; this.savingAccountAssembler = savingAccountAssembler;
@@ -137,6 +129,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
this.accountNumberFormatRepository = accountNumberFormatRepository; this.accountNumberFormatRepository = accountNumberFormatRepository;
this.savingsAccountWritePlatformService = savingsAccountWritePlatformService; this.savingsAccountWritePlatformService = savingsAccountWritePlatformService;
this.businessEventNotifierService = businessEventNotifierService ; this.businessEventNotifierService = businessEventNotifierService ;
this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService;
} }
/* /*
@@ -179,6 +172,15 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
generateAccountNumber(account); generateAccountNumber(account);
final Long savingsId = account.getId(); 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() // return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) // .withCommandId(command.commandId()) //
.withEntityId(savingsId) // .withEntityId(savingsId) //
@@ -343,6 +345,11 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId); final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId);
checkClientOrGroupActive(savingsAccount); checkClientOrGroupActive(savingsAccount);
entityDatatableChecksWritePlatformService.runTheCheckForProduct(savingsId, EntityTables.SAVING.getName(),
StatusEnum.APPROVE.getCode().longValue(),EntityTables.SAVING.getForeignKeyColumnNameOnDatatable(),
savingsAccount.productId());
final Map<String, Object> changes = savingsAccount.approveApplication(currentUser, command, DateUtils.getLocalDateOfTenant()); final Map<String, Object> changes = savingsAccount.approveApplication(currentUser, command, DateUtils.getLocalDateOfTenant());
if (!changes.isEmpty()) { if (!changes.isEmpty()) {
this.savingAccountRepository.save(savingsAccount); this.savingAccountRepository.save(savingsAccount);
@@ -411,6 +418,10 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId); final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId);
checkClientOrGroupActive(savingsAccount); checkClientOrGroupActive(savingsAccount);
entityDatatableChecksWritePlatformService.runTheCheckForProduct(savingsId, EntityTables.SAVING.getName(),
StatusEnum.REJECTED.getCode().longValue(),EntityTables.SAVING.getForeignKeyColumnNameOnDatatable(),
savingsAccount.productId());
final Map<String, Object> changes = savingsAccount.rejectApplication(currentUser, command, DateUtils.getLocalDateOfTenant()); final Map<String, Object> changes = savingsAccount.rejectApplication(currentUser, command, DateUtils.getLocalDateOfTenant());
if (!changes.isEmpty()) { if (!changes.isEmpty()) {
this.savingAccountRepository.save(savingsAccount); this.savingAccountRepository.save(savingsAccount);
@@ -445,6 +456,10 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId); final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId);
checkClientOrGroupActive(savingsAccount); checkClientOrGroupActive(savingsAccount);
entityDatatableChecksWritePlatformService.runTheCheckForProduct(savingsId, EntityTables.SAVING.getName(),
StatusEnum.WITHDRAWN.getCode().longValue(),EntityTables.SAVING.getForeignKeyColumnNameOnDatatable(),
savingsAccount.productId());
final Map<String, Object> changes = savingsAccount.applicantWithdrawsFromApplication(currentUser, command, final Map<String, Object> changes = savingsAccount.applicantWithdrawsFromApplication(currentUser, command,
DateUtils.getLocalDateOfTenant()); DateUtils.getLocalDateOfTenant());
if (!changes.isEmpty()) { if (!changes.isEmpty()) {
@@ -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);