You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ra...@apache.org on 2016/12/09 11:14:09 UTC

[2/5] incubator-fineract git commit: Entity datatable check implementation

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksWritePlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksWritePlatformServiceImpl.java
new file mode 100644
index 0000000..34f1312
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksWritePlatformServiceImpl.java
@@ -0,0 +1,315 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.PersistenceException;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.ApiParameterError;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
+import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
+import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
+import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
+import org.apache.fineract.infrastructure.dataqueries.domain.EntityDatatableChecks;
+import org.apache.fineract.infrastructure.dataqueries.domain.EntityDatatableChecksRepository;
+import org.apache.fineract.infrastructure.dataqueries.exception.*;
+import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.portfolio.loanproduct.service.LoanProductReadPlatformService;
+import org.apache.fineract.portfolio.savings.service.SavingsProductReadPlatformService;
+import org.apache.fineract.useradministration.domain.AppUser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataAccessException;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+@Service
+public class EntityDatatableChecksWritePlatformServiceImpl implements EntityDatatableChecksWritePlatformService {
+
+	private final static Logger logger = LoggerFactory.getLogger(EntityDatatableChecksWritePlatformServiceImpl.class);
+
+	private final PlatformSecurityContext context;
+	private final EntityDatatableChecksDataValidator fromApiJsonDeserializer;
+	private final EntityDatatableChecksRepository entityDatatableChecksRepository;
+	private final ReadWriteNonCoreDataService readWriteNonCoreDataService;
+	private final LoanProductReadPlatformService loanProductReadPlatformService;
+	private final SavingsProductReadPlatformService savingsProductReadPlatformService;
+	private final FromJsonHelper fromApiJsonHelper;
+	private final ConfigurationDomainService configurationDomainService;
+
+	@Autowired
+	public EntityDatatableChecksWritePlatformServiceImpl(final PlatformSecurityContext context,
+			final EntityDatatableChecksDataValidator fromApiJsonDeserializer,
+			final EntityDatatableChecksRepository entityDatatableChecksRepository,
+			final ReadWriteNonCoreDataService readWriteNonCoreDataService,
+			final LoanProductReadPlatformService loanProductReadPlatformService,
+			final SavingsProductReadPlatformService savingsProductReadPlatformService,
+			final FromJsonHelper fromApiJsonHelper,
+			final ConfigurationDomainService configurationDomainService) {
+		this.context = context;
+		this.fromApiJsonDeserializer = fromApiJsonDeserializer;
+		this.entityDatatableChecksRepository = entityDatatableChecksRepository;
+		this.readWriteNonCoreDataService = readWriteNonCoreDataService;
+		this.loanProductReadPlatformService = loanProductReadPlatformService;
+		this.savingsProductReadPlatformService = savingsProductReadPlatformService;
+		this.fromApiJsonHelper = fromApiJsonHelper;
+		this.configurationDomainService = configurationDomainService;
+	}
+
+	@Transactional
+	@Override
+	public CommandProcessingResult createCheck(final JsonCommand command) {
+
+		try {
+			this.context.authenticatedUser();
+
+			this.fromApiJsonDeserializer.validateForCreate(command.json());
+
+			// check if the datatable is linked to the entity
+
+			String datatableName = command.stringValueOfParameterNamed("datatableName");
+			DatatableData datatableData = this.readWriteNonCoreDataService.retrieveDatatable(datatableName);
+
+			if (datatableData == null) {
+				throw new DatatableNotFoundException(datatableName);
+			}
+
+			final String entity = command.stringValueOfParameterNamed("entity");
+			final String foreignKeyColumnName = EntityTables.getForeignKeyColumnNameOnDatatable(entity);
+			final boolean columnExist = datatableData.hasColumn(foreignKeyColumnName);
+
+			logger.info(datatableData.getRegisteredTableName() + "has column " + foreignKeyColumnName + " ? "
+					+ columnExist);
+
+			if (!columnExist) {
+				throw new EntityDatatableCheckNotSupportedException(datatableData.getRegisteredTableName(), entity);
+			}
+
+			final Long productId = command.longValueOfParameterNamed("productId");
+			final Long status = command.longValueOfParameterNamed("status");
+
+
+			List<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());
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataService.java
index 22529a3..e7f6364 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataService.java
@@ -54,6 +54,8 @@ public interface ReadWriteNonCoreDataService {
 
     CommandProcessingResult createNewDatatableEntry(String datatable, Long appTableId, JsonCommand command);
 
+    CommandProcessingResult createNewDatatableEntry(String datatable, Long appTableId, String json);
+
     CommandProcessingResult createPPIEntry(String datatable, Long appTableId, JsonCommand command);
 
     CommandProcessingResult updateDatatableEntryOneToOne(String datatable, Long appTableId, JsonCommand command);
@@ -68,4 +70,5 @@ public interface ReadWriteNonCoreDataService {
 
     String getDataTableName(String Url);
 
+    Long countDatatableEntries(String datatableName,Long appTableId,String foreignKeyColumn);
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java
index c40b949..e0a0696 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java
@@ -20,13 +20,7 @@ package org.apache.fineract.infrastructure.dataqueries.service;
 
 import java.lang.reflect.Type;
 import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 import javax.persistence.PersistenceException;
 import javax.sql.DataSource;
@@ -50,11 +44,7 @@ import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
 import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper;
 import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
 import org.apache.fineract.infrastructure.dataqueries.api.DataTableApiConstant;
-import org.apache.fineract.infrastructure.dataqueries.data.DataTableValidator;
-import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
-import org.apache.fineract.infrastructure.dataqueries.data.GenericResultsetData;
-import org.apache.fineract.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
-import org.apache.fineract.infrastructure.dataqueries.data.ResultsetRowData;
+import org.apache.fineract.infrastructure.dataqueries.data.*;
 import org.apache.fineract.infrastructure.dataqueries.exception.DatatableNotFoundException;
 import org.apache.fineract.infrastructure.dataqueries.exception.DatatableSystemErrorException;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
@@ -359,7 +349,12 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
     @Transactional
     @Override
     public CommandProcessingResult createNewDatatableEntry(final String dataTableName, final Long appTableId, final JsonCommand command) {
+        return createNewDatatableEntry(dataTableName, appTableId, command.json());
+    }
 
+    @Transactional
+    @Override
+    public CommandProcessingResult createNewDatatableEntry(final String dataTableName, final Long appTableId, final String json) {
         try {
             final String appTable = queryForApplicationTableName(dataTableName);
             final CommandProcessingResult commandProcessingResult = checkMainResourceExistsWithinScope(appTable, appTableId);
@@ -367,7 +362,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
             final List<ResultsetColumnHeaderData> columnHeaders = this.genericDataService.fillResultsetColumnHeaders(dataTableName);
 
             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);
 
@@ -378,29 +373,32 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
         } catch (final DataAccessException dve) {
             final Throwable cause = dve.getCause() ;
             final Throwable realCause = dve.getMostSpecificCause();
-            if (realCause.getMessage()
-                    .contains("Duplicate entry") || cause.getMessage()
-                    .contains("Duplicate entry")) { throw new PlatformDataIntegrityException(
-                            "error.msg.datatable.entry.duplicate", "An entry already exists for datatable `" + dataTableName
-                                    + "` and application table with identifier `" + appTableId + "`.",
-                            "dataTableName", dataTableName, appTableId); }
+            if (realCause.getMessage().contains("Duplicate entry") || cause.getMessage().contains("Duplicate entry")) {
+                throw new PlatformDataIntegrityException("error.msg.datatable.entry.duplicate", "An entry already exists for datatable `"
+                        + dataTableName + "` and application table with identifier `" + appTableId + "`.", "dataTableName", dataTableName,
+                        appTableId);
+            } else if (realCause.getMessage().contains("doesn't have a default value")
+                    || cause.getMessage().contains("doesn't have a default value")) { throw new PlatformDataIntegrityException(
+                    "error.msg.datatable.no.value.provided.for.required.fields", "No values provided for the datatable `" + dataTableName
+                            + "` and application table with identifier `" + appTableId + "`.", "dataTableName", dataTableName, appTableId); }
 
             logAsErrorUnexpectedDataIntegrityException(dve);
             throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue",
                     "Unknown data integrity issue with resource.");
-        }catch(final PersistenceException e) {
-        	final Throwable cause = e.getCause() ;
-            if (cause.getMessage()
-                    .contains("Duplicate entry")) { 
-            	throw new PlatformDataIntegrityException(
-                            "error.msg.datatable.entry.duplicate", "An entry already exists for datatable `" + dataTableName
-                                    + "` and application table with identifier `" + appTableId + "`.",
-                            "dataTableName", dataTableName, appTableId); }
+        } catch (final PersistenceException e) {
+            final Throwable cause = e.getCause();
+            if (cause.getMessage().contains("Duplicate entry")) {
+                throw new PlatformDataIntegrityException("error.msg.datatable.entry.duplicate", "An entry already exists for datatable `"
+                        + dataTableName + "` and application table with identifier `" + appTableId + "`.", "dataTableName", dataTableName,
+                        appTableId);
+            } else if (cause.getMessage().contains("doesn't have a default value")) { throw new PlatformDataIntegrityException(
+                    "error.msg.datatable.no.value.provided.for.required.fields", "No values provided for the datatable `" + dataTableName
+                            + "` and application table with identifier `" + appTableId + "`.", "dataTableName", dataTableName, appTableId); }
 
             logAsErrorUnexpectedDataIntegrityException(e);
             throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue",
                     "Unknown data integrity issue with resource.");
-        	
+
         }
     }
 
@@ -1722,4 +1720,14 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
 
         return true;
     }
+
+    @Override
+    public Long countDatatableEntries(final String datatableName, final Long appTableId, String foreignKeyColumn) {
+
+        final String sqlString = "SELECT COUNT(`" + foreignKeyColumn + "`) FROM `" + datatableName + "` WHERE `" + foreignKeyColumn + "`="
+                + appTableId;
+        final Long count = this.jdbcTemplate.queryForObject(sqlString, Long.class);
+        return count;
+    }
+
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientApiConstants.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientApiConstants.java
index e4f3ef1..fe5ec64 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientApiConstants.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientApiConstants.java
@@ -177,16 +177,18 @@ public class ClientApiConstants {
     public static final String officeOptionsParamName = "officeOptions";
     public static final String staffOptionsParamName = "staffOptions";
 
+    public static final String datatables = "datatables";
+
     public static final Set<String> CLIENT_CREATE_REQUEST_DATA_PARAMETERS = new HashSet<>(
             Arrays.asList(address,localeParamName, dateFormatParamName, groupIdParamName, accountNoParamName, externalIdParamName,
                     mobileNoParamName, firstnameParamName, middlenameParamName, lastnameParamName, fullnameParamName, officeIdParamName,
                     activeParamName, activationDateParamName, staffIdParamName, submittedOnDateParamName, savingsProductIdParamName,
                     dateOfBirthParamName, genderIdParamName, clientTypeIdParamName, clientClassificationIdParamName, 
-                    clientNonPersonDetailsParamName, displaynameParamName, legalFormIdParamName));
+                    clientNonPersonDetailsParamName, displaynameParamName, legalFormIdParamName, datatables));
     
     public static final Set<String> CLIENT_NON_PERSON_CREATE_REQUEST_DATA_PARAMETERS = new HashSet<>(
             Arrays.asList(address,localeParamName, dateFormatParamName, incorpNumberParamName, remarksParamName, incorpValidityTillParamName, 
-            		constitutionIdParamName, mainBusinessLineIdParamName));
+            		constitutionIdParamName, mainBusinessLineIdParamName, datatables));
 
     public static final Set<String> CLIENT_UPDATE_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName,
             dateFormatParamName, accountNoParamName, externalIdParamName, mobileNoParamName, firstnameParamName, middlenameParamName,

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientData.java
index bcba0fc..913ac17 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientData.java
@@ -27,6 +27,7 @@ import org.apache.commons.lang.builder.EqualsBuilder;
 import org.apache.commons.lang.builder.HashCodeBuilder;
 import org.apache.fineract.infrastructure.codes.data.CodeValueData;
 import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
 import org.apache.fineract.organisation.office.data.OfficeData;
 import org.apache.fineract.organisation.staff.data.StaffData;
 import org.apache.fineract.portfolio.address.data.AddressData;
@@ -101,12 +102,14 @@ final public class ClientData implements Comparable<ClientData> {
 
 	private final Boolean isAddressEnabled;
 
+    private final List<DatatableData> datatables;
+
     public static ClientData template(final Long officeId, final LocalDate joinedDate, final Collection<OfficeData> officeOptions,
             final Collection<StaffData> staffOptions, final Collection<CodeValueData> narrations,
             final Collection<CodeValueData> genderOptions, final Collection<SavingsProductData> savingProductOptions,
-            final Collection<CodeValueData> clientTypeOptions, final Collection<CodeValueData> clientClassificationOptions, 
-            final Collection<CodeValueData> clientNonPersonConstitutionOptions, final Collection<CodeValueData> clientNonPersonMainBusinessLineOptions,
-            final List<EnumOptionData> clientLegalFormOptions, final AddressData address,final Boolean isAddressEnabled) {
+            final Collection<CodeValueData> clientTypeOptions, final Collection<CodeValueData> clientClassificationOptions, final Collection<CodeValueData> clientNonPersonConstitutionOptions,
+            final Collection<CodeValueData> clientNonPersonMainBusinessLineOptions, final List<EnumOptionData> clientLegalFormOptions, final AddressData address,
+            final Boolean isAddressEnabled, final List<DatatableData> datatables) {
         final String accountNo = null;
         final EnumOptionData status = null;
         final CodeValueData subStatus = null;
@@ -141,7 +144,7 @@ final public class ClientData implements Comparable<ClientData> {
                 staffName, officeOptions, groups, staffOptions, narrations, genderOptions, timeline, savingProductOptions,
                 savingsProductId, savingsProductName, savingsAccountId, savingAccountOptions, clientType, clientClassification,
                 clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, 
-                clientNonPersonDetails, clientLegalFormOptions, legalForm,address, isAddressEnabled);
+                clientNonPersonDetails, clientLegalFormOptions, legalForm,address, isAddressEnabled, datatables);
 
     }
 
@@ -156,7 +159,7 @@ final public class ClientData implements Comparable<ClientData> {
                 clientData.savingsProductName, clientData.savingsAccountId, clientData.savingAccountOptions, clientData.clientType,
                 clientData.clientClassification, templateData.clientTypeOptions, templateData.clientClassificationOptions, 
                 templateData.clientNonPersonConstitutionOptions, templateData.clientNonPersonMainBusinessLineOptions, clientData.clientNonPersonDetails,
-                templateData.clientLegalFormOptions, clientData.legalForm, clientData.address,clientData.isAddressEnabled);
+                templateData.clientLegalFormOptions, clientData.legalForm, clientData.address,clientData.isAddressEnabled, null);
 
     }
 
@@ -172,7 +175,7 @@ final public class ClientData implements Comparable<ClientData> {
                 clientData.savingsProductName, clientData.savingsAccountId, savingAccountOptions, clientData.clientType,
                 clientData.clientClassification, clientData.clientTypeOptions, clientData.clientClassificationOptions,
                 clientData.clientNonPersonConstitutionOptions, clientData.clientNonPersonMainBusinessLineOptions, clientData.clientNonPersonDetails,
-                clientData.clientLegalFormOptions, clientData.legalForm,clientData.address, clientData.isAddressEnabled);
+                clientData.clientLegalFormOptions, clientData.legalForm,clientData.address, clientData.isAddressEnabled, null);
 
     }
 
@@ -186,7 +189,7 @@ final public class ClientData implements Comparable<ClientData> {
                 clientData.savingAccountOptions, clientData.clientType, clientData.clientClassification, clientData.clientTypeOptions,
                 clientData.clientClassificationOptions, clientData.clientNonPersonConstitutionOptions, clientData.clientNonPersonMainBusinessLineOptions, 
                 clientData.clientNonPersonDetails, clientData.clientLegalFormOptions, clientData.legalForm,clientData.address,
-				clientData.isAddressEnabled);
+				clientData.isAddressEnabled, null);
 
     }
 
@@ -230,7 +233,7 @@ final public class ClientData implements Comparable<ClientData> {
                 staffName, allowedOffices, groups, staffOptions, closureReasons, genderOptions, timeline, savingProductOptions,
                 savingsProductId, savingsProductName, savingsAccountId, savingAccountOptions, clientType, clientClassification,
                 clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, 
-                clientNonPerson, clientLegalFormOptions, legalForm,null,null);
+                clientNonPerson, clientLegalFormOptions, legalForm,null,null, null);
     }
 
     public static ClientData lookup(final Long id, final String displayName, final Long officeId, final String officeName) {
@@ -276,7 +279,7 @@ final public class ClientData implements Comparable<ClientData> {
                 staffName, allowedOffices, groups, staffOptions, closureReasons, genderOptions, timeline, savingProductOptions,
                 savingsProductId, savingsProductName, savingsAccountId, savingAccountOptions, clientType, clientClassification,
                 clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, 
-                clientNonPerson, clientLegalFormOptions, legalForm,null,null);
+                clientNonPerson, clientLegalFormOptions, legalForm,null,null, null);
 
     }
 
@@ -304,7 +307,7 @@ final public class ClientData implements Comparable<ClientData> {
                 staffName, allowedOffices, groups, staffOptions, closureReasons, genderOptions, timeline, savingProductOptions,
                 savingsProductId, savingsProductName, savingsAccountId, null, clientType, clientClassification, clientTypeOptions,
                 clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, clientNonPerson,
-                clientLegalFormOptions, legalForm,null,null);
+                clientLegalFormOptions, legalForm,null,null, null);
 
     }
 
@@ -321,7 +324,8 @@ final public class ClientData implements Comparable<ClientData> {
             final CodeValueData clientClassification, final Collection<CodeValueData> clientTypeOptions,
             final Collection<CodeValueData> clientClassificationOptions, final Collection<CodeValueData> clientNonPersonConstitutionOptions,
             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.status = status;
         if (status != null) {
@@ -382,7 +386,8 @@ final public class ClientData implements Comparable<ClientData> {
         this.clientNonPersonDetails = clientNonPerson;
         
       	this.address = address;
-				this.isAddressEnabled = isAddressEnabled;
+		this.isAddressEnabled = isAddressEnabled;
+        this.datatables = datatables;
 
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientDataValidator.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientDataValidator.java
index 6634916..4c2f538 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientDataValidator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientDataValidator.java
@@ -27,6 +27,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import com.google.gson.JsonArray;
 import org.apache.commons.lang.StringUtils;
 import org.apache.fineract.infrastructure.core.api.JsonCommand;
 import org.apache.fineract.infrastructure.core.data.ApiParameterError;
@@ -94,6 +95,13 @@ public final class ClientDataValidator {
             final Long savingsProductId = this.fromApiJsonHelper.extractLongNamed(ClientApiConstants.savingsProductIdParamName, element);
             baseDataValidator.reset().parameter(ClientApiConstants.savingsProductIdParamName).value(savingsProductId).ignoreIfNull()
                     .longGreaterThanZero();
+            /*if (savingsProductId != null && this.fromApiJsonHelper.parameterExists(ClientApiConstants.datatables, element)) {
+                final JsonArray datatables = this.fromApiJsonHelper.extractJsonArrayNamed(ClientApiConstants.datatables, element);
+                if (datatables.size() > 0) {
+                    baseDataValidator.reset().parameter(ClientApiConstants.savingsProductIdParamName).value(savingsProductId)
+                            .failWithCodeNoParameterAddedToErrorCode("should.not.be.used.with.datatables.parameter");
+                }
+            }*/
         }
 
         if (isFullnameProvided(element) || isIndividualNameProvided(element)) {
@@ -154,6 +162,10 @@ public final class ClientDataValidator {
                 final LocalDate joinedDate = this.fromApiJsonHelper.extractLocalDateNamed(ClientApiConstants.activationDateParamName,
                         element);
                 baseDataValidator.reset().parameter(ClientApiConstants.activationDateParamName).value(joinedDate).notNull();
+                /*if(this.fromApiJsonHelper.parameterExists(ClientApiConstants.datatables,element)){
+                    baseDataValidator.reset().parameter(ClientApiConstants.activeParamName).value(active)
+                            .failWithCodeNoParameterAddedToErrorCode("should.not.be.used.with.datatables.parameter");
+                }*/
             }
         } else {
             baseDataValidator.reset().parameter(ClientApiConstants.activeParamName).value(active).trueOrFalseRequired(false);
@@ -193,8 +205,13 @@ public final class ClientDataValidator {
         	final Integer legalFormId = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(ClientApiConstants.legalFormIdParamName, element);
             baseDataValidator.reset().parameter(ClientApiConstants.legalFormIdParamName).value(legalFormId).ignoreIfNull().inMinMaxRange(1, 2);
         }
-        
-        List<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);
         
         throwExceptionIfValidationWarningsExist(dataValidationErrors);
@@ -236,8 +253,8 @@ public final class ClientDataValidator {
                     element);
             baseDataValidator.reset().parameter(ClientApiConstants.mainBusinessLineIdParamName).value(mainBusinessLine).integerGreaterThanZero();
         }
-    	
-		return dataValidationErrors;    	
+
+		return dataValidationErrors;
     }
 
     private void validateIndividualNamePartsCannotBeUsedWithFullname(final JsonElement element, final DataValidatorBuilder baseDataValidator) {

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java
index bec5369..cab88f7 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java
@@ -36,6 +36,10 @@ import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.core.service.PaginationHelper;
 import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
+import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
+import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
+import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.organisation.office.data.OfficeData;
 import org.apache.fineract.organisation.office.service.OfficeReadPlatformService;
@@ -81,6 +85,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
     
     private final AddressReadPlatformService addressReadPlatformService;
     private final ConfigurationReadPlatformService configurationReadPlatformService;
+    private final EntityDatatableChecksReadService entityDatatableChecksReadService;
 
     @Autowired
     public ClientReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
@@ -88,7 +93,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
             final CodeValueReadPlatformService codeValueReadPlatformService,
             final SavingsProductReadPlatformService savingsProductReadPlatformService,
             final AddressReadPlatformService addressReadPlatformService,
-            final ConfigurationReadPlatformService configurationReadPlatformService) {
+            final ConfigurationReadPlatformService configurationReadPlatformService,
+            final EntityDatatableChecksReadService entityDatatableChecksReadService) {
         this.context = context;
         this.officeReadPlatformService = officeReadPlatformService;
         this.jdbcTemplate = new JdbcTemplate(dataSource);
@@ -97,6 +103,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
         this.savingsProductReadPlatformService = savingsProductReadPlatformService;
         this.addressReadPlatformService=addressReadPlatformService;
         this.configurationReadPlatformService=configurationReadPlatformService;
+        this.entityDatatableChecksReadService = entityDatatableChecksReadService;
     }
 
     @Override
@@ -149,9 +156,12 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
         
         final List<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,
                 clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions,
-                clientLegalFormOptions,address,isAddressEnabled);
+                clientLegalFormOptions,address,isAddressEnabled, datatableTemplates);
     }
 
     @Override
@@ -782,7 +792,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
         final Collection<CodeValueData> clientNonPersonMainBusinessLineOptions = null;
         final List<EnumOptionData> clientLegalFormOptions = null;
         return ClientData.template(null, null, null, null, narrations, null, null, clientTypeOptions, clientClassificationOptions, 
-        		clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, clientLegalFormOptions,null,null);
+        		clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, clientLegalFormOptions,null,null, null);
     }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java
index 9a25264..d2fa74c 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java
@@ -18,12 +18,7 @@
  */
 package org.apache.fineract.portfolio.client.service;
 
-
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
+import java.util.*;
 
 import javax.persistence.PersistenceException;
 
@@ -44,6 +39,9 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
 import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
 import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
+import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
+import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.organisation.office.domain.Office;
 import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
@@ -52,18 +50,8 @@ import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper;
 import org.apache.fineract.portfolio.address.service.AddressWritePlatformService;
 import org.apache.fineract.portfolio.client.api.ClientApiConstants;
 import org.apache.fineract.portfolio.client.data.ClientDataValidator;
-import org.apache.fineract.portfolio.client.domain.AccountNumberGenerator;
-import org.apache.fineract.portfolio.client.domain.Client;
-import org.apache.fineract.portfolio.client.domain.ClientNonPerson;
-import org.apache.fineract.portfolio.client.domain.ClientNonPersonRepositoryWrapper;
-import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
-import org.apache.fineract.portfolio.client.domain.ClientStatus;
-import org.apache.fineract.portfolio.client.domain.LegalForm;
-import org.apache.fineract.portfolio.client.exception.ClientActiveForUpdateException;
-import org.apache.fineract.portfolio.client.exception.ClientHasNoStaffException;
-import org.apache.fineract.portfolio.client.exception.ClientMustBePendingToBeDeletedException;
-import org.apache.fineract.portfolio.client.exception.InvalidClientSavingProductException;
-import org.apache.fineract.portfolio.client.exception.InvalidClientStateTransitionException;
+import org.apache.fineract.portfolio.client.domain.*;
+import org.apache.fineract.portfolio.client.exception.*;
 import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY;
 import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS;
 import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService;
@@ -121,7 +109,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
     private final ConfigurationReadPlatformService configurationReadPlatformService;
     private final AddressWritePlatformService addressWritePlatformService;
     private final BusinessEventNotifierService businessEventNotifierService;
-
+    private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
     @Autowired
     public ClientWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
             final ClientRepositoryWrapper clientRepository, final ClientNonPersonRepositoryWrapper clientNonPersonRepository,
@@ -134,7 +122,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
             final CommandProcessingService commandProcessingService, final ConfigurationDomainService configurationDomainService,
             final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository, final FromJsonHelper fromApiJsonHelper,
             final ConfigurationReadPlatformService configurationReadPlatformService,
-            final AddressWritePlatformService addressWritePlatformService, final BusinessEventNotifierService businessEventNotifierService) {
+            final AddressWritePlatformService addressWritePlatformService, final BusinessEventNotifierService businessEventNotifierService,
+            final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService) {
         this.context = context;
         this.clientRepository = clientRepository;
         this.clientNonPersonRepository = clientNonPersonRepository;
@@ -156,6 +145,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
         this.configurationReadPlatformService = configurationReadPlatformService;
         this.addressWritePlatformService = addressWritePlatformService;
         this.businessEventNotifierService = businessEventNotifierService;
+        this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService;
     }
 
     @Transactional
@@ -314,6 +304,15 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
                 this.addressWritePlatformService.addNewClientAddress(newClient, command);
             }
 
+            if(command.parameterExists(ClientApiConstants.datatables)){
+                this.entityDatatableChecksWritePlatformService.saveDatatables(StatusEnum.CREATE.getCode().longValue(),
+                        EntityTables.CLIENT.getName(), newClient.getId(), null,
+                        command.arrayOfParameterNamed(ClientApiConstants.datatables));
+            }
+
+            this.entityDatatableChecksWritePlatformService.runTheCheck(newClient.getId(), EntityTables.CLIENT.getName(),
+                    StatusEnum.CREATE.getCode().longValue(), EntityTables.CLIENT.getForeignKeyColumnNameOnDatatable());
+
             return new CommandProcessingResultBuilder() //
                     .withCommandId(command.commandId()) //
                     .withOfficeId(clientOffice.getId()) //
@@ -534,6 +533,9 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
             final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
             final LocalDate activationDate = command.localDateValueOfParameterNamed("activationDate");
 
+            entityDatatableChecksWritePlatformService.runTheCheck(clientId, EntityTables.CLIENT.getName(),
+                    StatusEnum.ACTIVATE.getCode().longValue(), EntityTables.CLIENT.getForeignKeyColumnNameOnDatatable());
+
             final AppUser currentUser = this.context.authenticatedUser();
             client.activate(currentUser, fmt, activationDate);
             CommandProcessingResult result = openSavingsAccount(client, fmt);
@@ -668,6 +670,9 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
                 throw new InvalidClientStateTransitionException("close", "date.cannot.before.client.actvation.date", errorMessage,
                         closureDate, client.getActivationLocalDate());
             }
+            entityDatatableChecksWritePlatformService.runTheCheck(clientId,EntityTables.CLIENT.getName(),
+                    StatusEnum.CLOSE.getCode().longValue(),EntityTables.CLIENT.getForeignKeyColumnNameOnDatatable());
+
             final List<Loan> clientLoans = this.loanRepositoryWrapper.findLoanByClientId(clientId);
             for (final Loan loan : clientLoans) {
                 final LoanStatusMapper loanStatus = new LoanStatusMapper(loan.status().getValue());

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java
index 367cae5..0195e99 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java
@@ -18,11 +18,7 @@
  */
 package org.apache.fineract.portfolio.group.api;
 
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.*;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -54,6 +50,10 @@ import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
 import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer;
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
+import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
+import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
+import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.portfolio.accountdetails.data.AccountSummaryCollectionData;
 import org.apache.fineract.portfolio.accountdetails.service.AccountDetailsReadPlatformService;
@@ -92,6 +92,7 @@ public class CentersApiResource {
     private final AccountDetailsReadPlatformService accountDetailsReadPlatformService;
     private final CalendarReadPlatformService calendarReadPlatformService;
     private final MeetingReadPlatformService meetingReadPlatformService;
+    private final EntityDatatableChecksReadService entityDatatableChecksReadService;
 
     @Autowired
     public CentersApiResource(final PlatformSecurityContext context, final CenterReadPlatformService centerReadPlatformService,
@@ -101,7 +102,8 @@ public class CentersApiResource {
             final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
             final CollectionSheetReadPlatformService collectionSheetReadPlatformService, final FromJsonHelper fromJsonHelper,
             final AccountDetailsReadPlatformService accountDetailsReadPlatformService,
-            final CalendarReadPlatformService calendarReadPlatformService, final MeetingReadPlatformService meetingReadPlatformService) {
+            final CalendarReadPlatformService calendarReadPlatformService, final MeetingReadPlatformService meetingReadPlatformService,
+            final EntityDatatableChecksReadService entityDatatableChecksReadService) {
         this.context = context;
         this.centerReadPlatformService = centerReadPlatformService;
         this.centerApiJsonSerializer = centerApiJsonSerializer;
@@ -114,6 +116,7 @@ public class CentersApiResource {
         this.accountDetailsReadPlatformService = accountDetailsReadPlatformService;
         this.calendarReadPlatformService = calendarReadPlatformService;
         this.meetingReadPlatformService = meetingReadPlatformService;
+        this.entityDatatableChecksReadService = entityDatatableChecksReadService;
     }
 
     @GET
@@ -134,6 +137,9 @@ public class CentersApiResource {
         }
 
         final CenterData template = this.centerReadPlatformService.retrieveTemplate(officeId, staffInSelectedOfficeOnly);
+        final List<DatatableData> datatableTemplates = this.entityDatatableChecksReadService
+                .retrieveTemplates(StatusEnum.CREATE.getCode().longValue(), EntityTables.GROUP.getName(), null);
+        template.setDatatables(datatableTemplates);
 
         final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
         return this.centerApiJsonSerializer.serialize(settings, template, GroupingTypesApiConstants.CENTER_RESPONSE_DATA_PARAMETERS);

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupingTypesApiConstants.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupingTypesApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupingTypesApiConstants.java
index bf1d6d0..bc3ebd0 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupingTypesApiConstants.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupingTypesApiConstants.java
@@ -87,13 +87,15 @@ public class GroupingTypesApiConstants {
     // staff centres parameters
     public static final String meetingFallCenters = "meetingFallCenters";
 
+    public static final String datatables = "datatables";
+
     public static final Set<String> CENTER_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName,
             dateFormatParamName, idParamName, nameParamName, externalIdParamName, officeIdParamName, staffIdParamName, activeParamName,
-            activationDateParamName, groupMembersParamName, submittedOnDateParamName));
+            activationDateParamName, groupMembersParamName, submittedOnDateParamName, datatables));
 
     public static final Set<String> GROUP_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName, dateFormatParamName,
             idParamName, nameParamName, externalIdParamName, centerIdParamName, officeIdParamName, staffIdParamName, activeParamName,
-            activationDateParamName, clientMembersParamName, collectionMeetingCalendar, submittedOnDateParamName));
+            activationDateParamName, clientMembersParamName, collectionMeetingCalendar, submittedOnDateParamName, datatables));
 
     public static final Set<String> GROUP_ROLES_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(roleParamName,
             clientIdParamName));
@@ -106,16 +108,16 @@ public class GroupingTypesApiConstants {
     public static final Set<String> CENTER_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName, nameParamName,
             externalIdParamName, officeIdParamName, officeNameParamName, staffIdParamName, staffNameParamName, hierarchyParamName,
             officeOptionsParamName, staffOptionsParamName, statusParamName, activeParamName, activationDateParamName, timeLine,
-            groupMembersParamName, collectionMeetingCalendar, closureReasons));
+            groupMembersParamName, collectionMeetingCalendar, closureReasons, datatables));
 
     public static final Set<String> CENTER_GROUP_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName, nameParamName,
             externalIdParamName, officeIdParamName, officeNameParamName, staffIdParamName, staffNameParamName, hierarchyParamName,
-            officeOptionsParamName, staffOptionsParamName, clientOptionsParamName));
+            officeOptionsParamName, staffOptionsParamName, clientOptionsParamName, datatables));
 
     public static final Set<String> GROUP_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName, nameParamName,
             externalIdParamName, officeIdParamName, officeNameParamName, "parentId", "parentName", staffIdParamName, staffNameParamName,
             hierarchyParamName, officeOptionsParamName, statusParamName, activeParamName, activationDateParamName, staffOptionsParamName,
-            clientOptionsParamName, timeLine));
+            clientOptionsParamName, timeLine, datatables));
 
     public static final Set<String> ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName,
             dateFormatParamName, activationDateParamName));

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java
index 033a8db..96dc132 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java
@@ -53,6 +53,10 @@ import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
 import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer;
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
+import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
+import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
+import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.portfolio.accountdetails.data.AccountSummaryCollectionData;
 import org.apache.fineract.portfolio.accountdetails.service.AccountDetailsReadPlatformService;
@@ -99,6 +103,7 @@ public class GroupsApiResource {
     private final AccountDetailsReadPlatformService accountDetailsReadPlatformService;
     private final CalendarReadPlatformService calendarReadPlatformService;
     private final MeetingReadPlatformService meetingReadPlatformService;
+    private final EntityDatatableChecksReadService entityDatatableChecksReadService;
 
     @Autowired
     public GroupsApiResource(final PlatformSecurityContext context, final GroupReadPlatformService groupReadPlatformService,
@@ -111,7 +116,8 @@ public class GroupsApiResource {
             final CollectionSheetReadPlatformService collectionSheetReadPlatformService, final FromJsonHelper fromJsonHelper,
             final GroupRolesReadPlatformService groupRolesReadPlatformService,
             final AccountDetailsReadPlatformService accountDetailsReadPlatformService,
-            final CalendarReadPlatformService calendarReadPlatformService, final MeetingReadPlatformService meetingReadPlatformService) {
+            final CalendarReadPlatformService calendarReadPlatformService, final MeetingReadPlatformService meetingReadPlatformService,
+            final EntityDatatableChecksReadService entityDatatableChecksReadService) {
 
         this.context = context;
         this.groupReadPlatformService = groupReadPlatformService;
@@ -128,6 +134,7 @@ public class GroupsApiResource {
         this.accountDetailsReadPlatformService = accountDetailsReadPlatformService;
         this.calendarReadPlatformService = calendarReadPlatformService;
         this.meetingReadPlatformService = meetingReadPlatformService;
+        this.entityDatatableChecksReadService = entityDatatableChecksReadService;
     }
 
     @GET
@@ -148,8 +155,11 @@ public class GroupsApiResource {
                     GroupingTypesApiConstants.GROUP_RESPONSE_DATA_PARAMETERS);
         }
 
+        final List<DatatableData> datatableTemplates = this.entityDatatableChecksReadService
+                .retrieveTemplates(StatusEnum.CREATE.getCode().longValue(), EntityTables.GROUP.getName(), null);
         if (centerId != null) {
             final GroupGeneralData centerGroupTemplate = this.centerReadPlatformService.retrieveCenterGroupTemplate(centerId);
+            centerGroupTemplate.setDatatables(datatableTemplates);
             final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
             return this.groupGeneralApiJsonSerializer.serialize(settings, centerGroupTemplate,
                     GroupingTypesApiConstants.CENTER_GROUP_RESPONSE_DATA_PARAMETERS);
@@ -157,6 +167,8 @@ public class GroupsApiResource {
 
         final GroupGeneralData groupTemplate = this.groupReadPlatformService.retrieveTemplate(officeId, isCenterGroup,
                 staffInSelectedOfficeOnly);
+        groupTemplate.setDatatables(datatableTemplates);
+
         final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
         return this.groupGeneralApiJsonSerializer.serialize(settings, groupTemplate,
                 GroupingTypesApiConstants.GROUP_RESPONSE_DATA_PARAMETERS);

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterData.java
index b05267d..2d2828d 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterData.java
@@ -20,9 +20,11 @@ package org.apache.fineract.portfolio.group.data;
 
 import java.math.BigDecimal;
 import java.util.Collection;
+import java.util.List;
 
 import org.apache.fineract.infrastructure.codes.data.CodeValueData;
 import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
 import org.apache.fineract.organisation.office.data.OfficeData;
 import org.apache.fineract.organisation.staff.data.StaffData;
 import org.apache.fineract.portfolio.calendar.data.CalendarData;
@@ -63,6 +65,8 @@ public class CenterData {
     private final BigDecimal totaldue;
     private final BigDecimal installmentDue;
 
+    private List<DatatableData> datatables = null;
+
     public static CenterData template(final Long officeId, final String accountNo, final LocalDate activationDate,
             final Collection<OfficeData> officeOptions, final Collection<StaffData> staffOptions,
             final Collection<GroupGeneralData> groupMembersOptions, final BigDecimal totalCollected, final BigDecimal totalOverdue,
@@ -204,4 +208,8 @@ public class CenterData {
     public String getStaffName() {
         return this.staffName;
     }
+
+    public void setDatatables(final List<DatatableData> datatables) {
+        this.datatables = datatables;
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupGeneralData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupGeneralData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupGeneralData.java
index 942e655..d6c2259 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupGeneralData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupGeneralData.java
@@ -19,9 +19,11 @@
 package org.apache.fineract.portfolio.group.data;
 
 import java.util.Collection;
+import java.util.List;
 
 import org.apache.fineract.infrastructure.codes.data.CodeValueData;
 import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
 import org.apache.fineract.organisation.office.data.OfficeData;
 import org.apache.fineract.organisation.staff.data.StaffData;
 import org.apache.fineract.portfolio.calendar.data.CalendarData;
@@ -70,6 +72,8 @@ public class GroupGeneralData {
     private final Collection<CodeValueData> closureReasons;
     private final GroupTimelineData timeline;
 
+    private List<DatatableData> datatables = null;
+
     public static GroupGeneralData lookup(final Long groupId, final String accountNo, final String groupName) {
         final Collection<ClientData> clientMembers = null;
         final Collection<GroupRoleData> groupRoles = null;
@@ -256,4 +260,8 @@ public class GroupGeneralData {
     public Collection<ClientData> clientMembers() {
         return this.clientMembers;
     }
+
+    public void setDatatables(final List<DatatableData> datatables) {
+            this.datatables = datatables;
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/serialization/GroupingTypesDataValidator.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/serialization/GroupingTypesDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/serialization/GroupingTypesDataValidator.java
index bf5362d..b30de36 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/serialization/GroupingTypesDataValidator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/serialization/GroupingTypesDataValidator.java
@@ -26,6 +26,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import com.google.gson.JsonArray;
 import org.apache.commons.lang.StringUtils;
 import org.apache.fineract.infrastructure.core.api.JsonCommand;
 import org.apache.fineract.infrastructure.core.data.ApiParameterError;
@@ -116,6 +117,11 @@ public final class GroupingTypesDataValidator {
             baseDataValidator.reset().parameter(GroupingTypesApiConstants.submittedOnDateParamName).value(submittedOnDate).notNull();
         }
 
+        if(this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.datatables, element)){
+            final JsonArray datatables = this.fromApiJsonHelper.extractJsonArrayNamed(GroupingTypesApiConstants.datatables, element);
+            baseDataValidator.reset().parameter(GroupingTypesApiConstants.datatables).value(datatables).notNull().jsonArrayNotEmpty();
+        }
+
         throwExceptionIfValidationWarningsExist(dataValidationErrors);
     }
 
@@ -180,6 +186,11 @@ public final class GroupingTypesDataValidator {
             baseDataValidator.reset().parameter(GroupingTypesApiConstants.submittedOnDateParamName).value(submittedOnDate).notNull();
         }
 
+        if(this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.datatables, element)){
+            final JsonArray datatables = this.fromApiJsonHelper.extractJsonArrayNamed(GroupingTypesApiConstants.datatables, element);
+            baseDataValidator.reset().parameter(GroupingTypesApiConstants.datatables).value(datatables).notNull().jsonArrayNotEmpty();
+        }
+
         throwExceptionIfValidationWarningsExist(dataValidationErrors);
     }
 
@@ -240,6 +251,11 @@ public final class GroupingTypesDataValidator {
             baseDataValidator.reset().parameter(GroupingTypesApiConstants.submittedOnDateParamName).value(submittedOnDate).notNull();
         }
 
+        if(this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.datatables, element)){
+            final JsonArray datatables = this.fromApiJsonHelper.extractJsonArrayNamed(GroupingTypesApiConstants.datatables, element);
+            baseDataValidator.reset().parameter(GroupingTypesApiConstants.datatables).value(datatables).notNull().jsonArrayNotEmpty();
+        }
+
         throwExceptionIfValidationWarningsExist(dataValidationErrors);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java
index 0cfc7f9..19b4a41 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java
@@ -18,13 +18,7 @@
  */
 package org.apache.fineract.portfolio.group.service;
 
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 import javax.persistence.PersistenceException;
 
@@ -43,33 +37,24 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
 import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
 import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
 import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
+import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
+import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.organisation.office.domain.Office;
 import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
 import org.apache.fineract.organisation.office.exception.InvalidOfficeException;
 import org.apache.fineract.organisation.staff.domain.Staff;
 import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper;
+import org.apache.fineract.portfolio.calendar.domain.*;
 import org.apache.fineract.portfolio.calendar.domain.Calendar;
-import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
-import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
-import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository;
-import org.apache.fineract.portfolio.calendar.domain.CalendarType;
 import org.apache.fineract.portfolio.client.domain.AccountNumberGenerator;
 import org.apache.fineract.portfolio.client.domain.Client;
 import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
 import org.apache.fineract.portfolio.client.service.LoanStatusMapper;
 import org.apache.fineract.portfolio.group.api.GroupingTypesApiConstants;
-import org.apache.fineract.portfolio.group.domain.Group;
-import org.apache.fineract.portfolio.group.domain.GroupLevel;
-import org.apache.fineract.portfolio.group.domain.GroupLevelRepository;
-import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper;
-import org.apache.fineract.portfolio.group.domain.GroupTypes;
-import org.apache.fineract.portfolio.group.exception.GroupAccountExistsException;
-import org.apache.fineract.portfolio.group.exception.GroupHasNoStaffException;
-import org.apache.fineract.portfolio.group.exception.GroupMemberCountNotInPermissibleRangeException;
-import org.apache.fineract.portfolio.group.exception.GroupMustBePendingToBeDeletedException;
-import org.apache.fineract.portfolio.group.exception.InvalidGroupLevelException;
-import org.apache.fineract.portfolio.group.exception.InvalidGroupStateTransitionException;
+import org.apache.fineract.portfolio.group.domain.*;
+import org.apache.fineract.portfolio.group.exception.*;
 import org.apache.fineract.portfolio.group.serialization.GroupingTypesDataValidator;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
@@ -109,6 +94,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
     private final SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper;
     private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository;
     private final AccountNumberGenerator accountNumberGenerator;
+    private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
 
     @Autowired
     public GroupingTypesWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -119,7 +105,8 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
             final CodeValueRepositoryWrapper codeValueRepository, final CommandProcessingService commandProcessingService,
             final CalendarInstanceRepository calendarInstanceRepository, final ConfigurationDomainService configurationDomainService,
             final LoanRepositoryWrapper loanRepositoryWrapper, 
-            final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository, final AccountNumberGenerator accountNumberGenerator) {
+            final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository, final AccountNumberGenerator accountNumberGenerator,
+            final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService) {
         this.context = context;
         this.groupRepository = groupRepository;
         this.clientRepositoryWrapper = clientRepositoryWrapper;
@@ -136,6 +123,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
         this.loanRepositoryWrapper = loanRepositoryWrapper;
         this.accountNumberFormatRepository = accountNumberFormatRepository;
         this.accountNumberGenerator = accountNumberGenerator;
+        this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService;
     }
 
     private CommandProcessingResult createGroupingType(final JsonCommand command, final GroupTypes groupingType, final Long centerId) {
@@ -219,6 +207,16 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
 
             this.groupRepository.saveAndFlush(newGroup);
             newGroup.captureStaffHistoryDuringCenterCreation(staff, activationDate);
+
+            if(command.parameterExists(GroupingTypesApiConstants.datatables)){
+                this.entityDatatableChecksWritePlatformService.saveDatatables(StatusEnum.CREATE.getCode().longValue(),
+                        EntityTables.GROUP.getName(), newGroup.getId(), null,
+                        command.arrayOfParameterNamed(GroupingTypesApiConstants.datatables));
+            }
+
+            this.entityDatatableChecksWritePlatformService.runTheCheck(newGroup.getId(), EntityTables.GROUP.getName(),
+                    StatusEnum.CREATE.getCode().longValue(), EntityTables.GROUP.getForeignKeyColumnNameOnDatatable());
+
             return new CommandProcessingResultBuilder() //
                     .withCommandId(command.commandId()) //
                     .withOfficeId(groupOffice.getId()) //
@@ -296,6 +294,10 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
             final LocalDate activationDate = command.localDateValueOfParameterNamed("activationDate");
 
             validateOfficeOpeningDateisAfterGroupOrCenterOpeningDate(group.getOffice(), group.getGroupLevel(), activationDate);
+
+            entityDatatableChecksWritePlatformService.runTheCheck(groupId, EntityTables.GROUP.getName(),
+                    StatusEnum.ACTIVATE.getCode().longValue(), EntityTables.GROUP.getForeignKeyColumnNameOnDatatable());
+
             group.activate(currentUser, activationDate);
 
             this.groupRepository.saveAndFlush(group);
@@ -585,6 +587,9 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
 
         validateLoansAndSavingsForGroupOrCenterClose(group, closureDate);
 
+        entityDatatableChecksWritePlatformService.runTheCheck(groupId, EntityTables.GROUP.getName(),
+                StatusEnum.CLOSE.getCode().longValue(),EntityTables.GROUP.getForeignKeyColumnNameOnDatatable());
+
         group.close(currentUser, closureReason, closureDate);
 
         this.groupRepository.saveAndFlush(group);
@@ -657,6 +662,10 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
 
         validateLoansAndSavingsForGroupOrCenterClose(center, closureDate);
 
+        entityDatatableChecksWritePlatformService.runTheCheck(centerId, EntityTables.GROUP.getName(),
+                StatusEnum.ACTIVATE.getCode().longValue(), EntityTables.GROUP.getForeignKeyColumnNameOnDatatable());
+
+
         center.close(currentUser, closureReason, closureDate);
 
         this.groupRepository.saveAndFlush(center);

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java
index d312324..6e5376a 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java
@@ -123,4 +123,5 @@ public interface LoanApiConstants {
     public static final String loanIdToClose = "loanIdToClose";
     public static final String topupAmount = "topupAmount";
 
+    public static final String datatables = "datatables";
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
index c236e37..bded415 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
@@ -20,12 +20,7 @@ package org.apache.fineract.portfolio.loanaccount.api;
 
 import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.interestType;
 
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -58,6 +53,10 @@ import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSer
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
+import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
+import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
+import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.organisation.monetary.data.CurrencyData;
 import org.apache.fineract.organisation.staff.data.StaffData;
@@ -139,7 +138,8 @@ public class LoansApiResource {
             "loanOfficerOptions", "loanPurposeOptions", "loanCollateralOptions", "chargeTemplate", "calendarOptions",
             "syncDisbursementWithMeeting", "loanCounter", "loanProductCounter", "notes", "accountLinkingOptions", "linkedAccount",
             "interestRateDifferential", "isFloatingInterestRate", "interestRatesPeriods", LoanApiConstants.canUseForTopup,
-            LoanApiConstants.isTopup, LoanApiConstants.loanIdToClose, LoanApiConstants.topupAmount, LoanApiConstants.clientActiveLoanOptions));
+            LoanApiConstants.isTopup, LoanApiConstants.loanIdToClose, LoanApiConstants.topupAmount, LoanApiConstants.clientActiveLoanOptions,
+            LoanApiConstants.datatables));
 
     private final Set<String> LOAN_APPROVAL_DATA_PARAMETERS = new HashSet<>(Arrays.asList("approvalDate", "approvalAmount"));
     private final String resourceNameForPermissions = "LOAN";
@@ -168,6 +168,7 @@ public class LoansApiResource {
     private final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService;
     private final LoanScheduleHistoryReadPlatformService loanScheduleHistoryReadPlatformService;
     private final AccountDetailsReadPlatformService accountDetailsReadPlatformService;
+    private final EntityDatatableChecksReadService entityDatatableChecksReadService;
 
     @Autowired
     public LoansApiResource(final PlatformSecurityContext context, final LoanReadPlatformService loanReadPlatformService,
@@ -187,7 +188,8 @@ public class LoansApiResource {
             final PortfolioAccountReadPlatformService portfolioAccountReadPlatformServiceImpl,
             final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService,
             final LoanScheduleHistoryReadPlatformService loanScheduleHistoryReadPlatformService,
-            final AccountDetailsReadPlatformService accountDetailsReadPlatformService) {
+            final AccountDetailsReadPlatformService accountDetailsReadPlatformService,
+            final EntityDatatableChecksReadService entityDatatableChecksReadService) {
         this.context = context;
         this.loanReadPlatformService = loanReadPlatformService;
         this.loanProductReadPlatformService = loanProductReadPlatformService;
@@ -212,6 +214,7 @@ public class LoansApiResource {
         this.accountAssociationsReadPlatformService = accountAssociationsReadPlatformService;
         this.loanScheduleHistoryReadPlatformService = loanScheduleHistoryReadPlatformService;
         this.accountDetailsReadPlatformService = accountDetailsReadPlatformService;
+        this.entityDatatableChecksReadService = entityDatatableChecksReadService;
     }
 
     /*
@@ -347,6 +350,10 @@ public class LoansApiResource {
             newLoanAccount = LoanAccountData.associationsAndTemplate(newLoanAccount, productOptions, allowedLoanOfficers, calendarOptions,
                     accountLinkingOptions);
         }
+        final List<DatatableData> datatableTemplates = this.entityDatatableChecksReadService
+                .retrieveTemplates(StatusEnum.CREATE.getCode().longValue(), EntityTables.LOAN.getName(), productId);
+        newLoanAccount.setDatatables(datatableTemplates);
+
         final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
         return this.toApiJsonSerializer.serialize(settings, newLoanAccount, this.LOAN_DATA_PARAMETERS);
     }