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:08 UTC

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

Repository: incubator-fineract
Updated Branches:
  refs/heads/develop b60779b9a -> 09629933e


http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
index 5a250b3..5109c3e 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
@@ -19,15 +19,13 @@
 package org.apache.fineract.portfolio.loanaccount.data;
 
 import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.*;
 
 import javax.persistence.Transient;
 
 import org.apache.fineract.infrastructure.codes.data.CodeValueData;
 import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
 import org.apache.fineract.organisation.monetary.data.CurrencyData;
 import org.apache.fineract.organisation.staff.data.StaffData;
 import org.apache.fineract.portfolio.account.data.PortfolioAccountData;
@@ -214,6 +212,8 @@ public class LoanAccountData {
     private final Integer minimumGap;
     private final Integer maximumGap;
 
+    private List<DatatableData> datatables = null;
+
     /**
      * Used to produce a {@link LoanAccountData} with only collateral options
      * for now.
@@ -1618,4 +1618,8 @@ public class LoanAccountData {
     public BigDecimal getInterestRateDifferential() {
         return this.interestRateDifferential;
     }
+
+    public void setDatatables(final List<DatatableData> datatables) {
+            this.datatables = datatables;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java
index 8f871b0..523207d 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java
@@ -37,6 +37,7 @@ import org.apache.fineract.infrastructure.core.exception.UnsupportedParameterExc
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
 import org.apache.fineract.portfolio.accountdetails.domain.AccountType;
 import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
+import org.apache.fineract.portfolio.client.api.ClientApiConstants;
 import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
@@ -92,7 +93,7 @@ public final class LoanApplicationCommandFromApiJsonHelper {
             LoanApiConstants.linkAccountIdParameterName, LoanApiConstants.disbursementDataParameterName,
             LoanApiConstants.emiAmountParameterName, LoanApiConstants.maxOutstandingBalanceParameterName,
             LoanProductConstants.graceOnArrearsAgeingParameterName, LoanApiConstants.createStandingInstructionAtDisbursementParameterName,
-            LoanApiConstants.isTopup, LoanApiConstants.loanIdToClose));
+            LoanApiConstants.isTopup, LoanApiConstants.loanIdToClose, LoanApiConstants.datatables));
 
     private final FromJsonHelper fromApiJsonHelper;
     private final CalculateLoanScheduleQueryFromApiJsonHelper apiJsonHelper;
@@ -482,6 +483,11 @@ public final class LoanApplicationCommandFromApiJsonHelper {
                 }
             }
         }
+        if(this.fromApiJsonHelper.parameterExists(LoanApiConstants.datatables, element)){
+            final JsonArray datatables = this.fromApiJsonHelper.extractJsonArrayNamed(LoanApiConstants.datatables, element);
+            baseDataValidator.reset().parameter(LoanApiConstants.datatables).value(datatables).notNull().jsonArrayNotEmpty();
+        }
+
         validateLoanMultiDisbursementdate(element, baseDataValidator, expectedDisbursementDate, principal);
         validatePartialPeriodSupport(interestCalculationPeriodType, baseDataValidator, element, loanProduct);
         if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
index 221273f..fe17b5c 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
@@ -19,14 +19,8 @@
 package org.apache.fineract.portfolio.loanaccount.service;
 
 import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.persistence.EntityExistsException;
+import java.util.*;
+
 import javax.persistence.PersistenceException;
 
 import org.apache.commons.lang.StringUtils;
@@ -48,12 +42,11 @@ import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRu
 import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
 import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
+import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
+import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService;
 import org.apache.fineract.infrastructure.entityaccess.FineractEntityAccessConstants;
-import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityAccessType;
-import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityRelation;
-import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityRelationRepository;
-import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityToEntityMapping;
-import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityToEntityMappingRepository;
+import org.apache.fineract.infrastructure.entityaccess.domain.*;
 import org.apache.fineract.infrastructure.entityaccess.exception.NotOfficeSpecificProductException;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.organisation.staff.domain.Staff;
@@ -61,13 +54,8 @@ import org.apache.fineract.portfolio.account.domain.AccountAssociationType;
 import org.apache.fineract.portfolio.account.domain.AccountAssociations;
 import org.apache.fineract.portfolio.account.domain.AccountAssociationsRepository;
 import org.apache.fineract.portfolio.accountdetails.domain.AccountType;
+import org.apache.fineract.portfolio.calendar.domain.*;
 import org.apache.fineract.portfolio.calendar.domain.Calendar;
-import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
-import org.apache.fineract.portfolio.calendar.domain.CalendarFrequencyType;
-import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
-import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository;
-import org.apache.fineract.portfolio.calendar.domain.CalendarRepository;
-import org.apache.fineract.portfolio.calendar.domain.CalendarType;
 import org.apache.fineract.portfolio.calendar.exception.CalendarNotFoundException;
 import org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformService;
 import org.apache.fineract.portfolio.charge.domain.Charge;
@@ -88,18 +76,7 @@ import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
 import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
 import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
 import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
-import org.apache.fineract.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine;
-import org.apache.fineract.portfolio.loanaccount.domain.Loan;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanTopupDetails;
+import org.apache.fineract.portfolio.loanaccount.domain.*;
 import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationDateException;
 import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeDeleted;
 import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified;
@@ -111,11 +88,7 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanSchedu
 import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationCommandFromApiJsonHelper;
 import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationTransitionApiJsonValidator;
 import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
-import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
-import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
-import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
-import org.apache.fineract.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
-import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
+import org.apache.fineract.portfolio.loanproduct.domain.*;
 import org.apache.fineract.portfolio.loanproduct.exception.LinkedAccountRequiredException;
 import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException;
 import org.apache.fineract.portfolio.loanproduct.serialization.LoanProductDataValidator;
@@ -170,6 +143,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
     private final LoanScheduleAssembler loanScheduleAssembler;
     private final LoanUtilService loanUtilService;
     private final CalendarReadPlatformService calendarReadPlatformService;
+    private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
     private final GlobalConfigurationRepositoryWrapper globalConfigurationRepository;
     private final FineractEntityToEntityMappingRepository repository;
     private final FineractEntityRelationRepository fineractEntityRelationRepository;
@@ -194,7 +168,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
             final BusinessEventNotifierService businessEventNotifierService, final ConfigurationDomainService configurationDomainService,
             final LoanScheduleAssembler loanScheduleAssembler, final LoanUtilService loanUtilService, 
             final CalendarReadPlatformService calendarReadPlatformService, final GlobalConfigurationRepositoryWrapper globalConfigurationRepository,
-            final FineractEntityToEntityMappingRepository repository, final FineractEntityRelationRepository fineractEntityRelationRepository) {
+            final FineractEntityToEntityMappingRepository repository, final FineractEntityRelationRepository fineractEntityRelationRepository,
+            final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService) {
         this.context = context;
         this.fromJsonHelper = fromJsonHelper;
         this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator;
@@ -225,6 +200,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
         this.loanScheduleAssembler = loanScheduleAssembler;
         this.loanUtilService = loanUtilService;
         this.calendarReadPlatformService = calendarReadPlatformService;
+        this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService;
         this.globalConfigurationRepository = globalConfigurationRepository;
         this.repository = repository;
         this.fineractEntityRelationRepository = fineractEntityRelationRepository;
@@ -408,6 +384,17 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
                 this.accountAssociationsRepository.save(accountAssociations);
             }
 
+            if(command.parameterExists(LoanApiConstants.datatables)){
+                this.entityDatatableChecksWritePlatformService.saveDatatables(StatusEnum.CREATE.getCode().longValue(),
+                        EntityTables.LOAN.getName(), newLoanApplication.getId(), newLoanApplication.productId(),
+                        command.arrayOfParameterNamed(LoanApiConstants.datatables));
+            }
+
+            this.entityDatatableChecksWritePlatformService.runTheCheckForProduct(newLoanApplication.getId(),
+                    EntityTables.LOAN.getName(), StatusEnum.CREATE.getCode().longValue(),
+                    EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), newLoanApplication.productId());
+
+
             return new CommandProcessingResultBuilder() //
                     .withCommandId(command.commandId()) //
                     .withEntityId(newLoanApplication.getId()) //
@@ -1107,6 +1094,9 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
         final Map<String, Object> changes = loan.loanApplicationApproval(currentUser, command, disbursementDataArray,
                 defaultLoanLifecycleStateMachine());
 
+        entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(),
+                StatusEnum.APPROVE.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId());
+
         if (!changes.isEmpty()) {
 
             // If loan approved amount less than loan demanded amount, then need
@@ -1221,8 +1211,12 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
         this.loanApplicationTransitionApiJsonValidator.validateRejection(command.json());
 
         final Loan loan = retrieveLoanBy(loanId);
+
         checkClientOrGroupActive(loan);
 
+        entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(),
+                StatusEnum.REJECTED.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(),loan.productId());
+
         final Map<String, Object> changes = loan.loanApplicationRejection(currentUser, command, defaultLoanLifecycleStateMachine());
         if (!changes.isEmpty()) {
             this.loanRepositoryWrapper.save(loan);
@@ -1256,6 +1250,9 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
         final Loan loan = retrieveLoanBy(loanId);
         checkClientOrGroupActive(loan);
 
+        entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(),
+                StatusEnum.WITHDRAWN.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId());
+
         final Map<String, Object> changes = loan.loanApplicationWithdrawnByApplicant(currentUser, command,
                 defaultLoanLifecycleStateMachine());
         if (!changes.isEmpty()) {

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
index 8850bf4..95b4c94 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
@@ -19,17 +19,7 @@
 package org.apache.fineract.portfolio.loanaccount.service;
 
 import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
@@ -46,6 +36,9 @@ import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati
 import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavailableException;
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
+import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
+import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService;
 import org.apache.fineract.infrastructure.jobs.annotation.CronTarget;
 import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
 import org.apache.fineract.infrastructure.jobs.service.JobName;
@@ -63,44 +56,22 @@ import org.apache.fineract.organisation.workingdays.domain.WorkingDaysRepository
 import org.apache.fineract.portfolio.account.PortfolioAccountType;
 import org.apache.fineract.portfolio.account.data.AccountTransferDTO;
 import org.apache.fineract.portfolio.account.data.PortfolioAccountData;
-import org.apache.fineract.portfolio.account.domain.AccountAssociationType;
-import org.apache.fineract.portfolio.account.domain.AccountAssociations;
-import org.apache.fineract.portfolio.account.domain.AccountAssociationsRepository;
-import org.apache.fineract.portfolio.account.domain.AccountTransferDetailRepository;
-import org.apache.fineract.portfolio.account.domain.AccountTransferDetails;
-import org.apache.fineract.portfolio.account.domain.AccountTransferRecurrenceType;
-import org.apache.fineract.portfolio.account.domain.AccountTransferRepository;
-import org.apache.fineract.portfolio.account.domain.AccountTransferStandingInstruction;
-import org.apache.fineract.portfolio.account.domain.AccountTransferTransaction;
-import org.apache.fineract.portfolio.account.domain.AccountTransferType;
-import org.apache.fineract.portfolio.account.domain.StandingInstructionPriority;
-import org.apache.fineract.portfolio.account.domain.StandingInstructionStatus;
-import org.apache.fineract.portfolio.account.domain.StandingInstructionType;
+import org.apache.fineract.portfolio.account.domain.*;
 import org.apache.fineract.portfolio.account.service.AccountAssociationsReadPlatformService;
 import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
 import org.apache.fineract.portfolio.account.service.AccountTransfersWritePlatformService;
 import org.apache.fineract.portfolio.accountdetails.domain.AccountType;
+import org.apache.fineract.portfolio.calendar.domain.*;
 import org.apache.fineract.portfolio.calendar.domain.Calendar;
-import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
-import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
-import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository;
-import org.apache.fineract.portfolio.calendar.domain.CalendarRepository;
-import org.apache.fineract.portfolio.calendar.domain.CalendarType;
 import org.apache.fineract.portfolio.calendar.exception.CalendarParameterUpdateNotSupportedException;
 import org.apache.fineract.portfolio.charge.domain.Charge;
 import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode;
 import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
-import org.apache.fineract.portfolio.charge.exception.ChargeCannotBeUpdatedException;
-import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeAddedException;
-import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeDeletedException;
+import org.apache.fineract.portfolio.charge.exception.*;
 import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeDeletedException.LOAN_CHARGE_CANNOT_BE_DELETED_REASON;
-import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBePayedException;
 import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBePayedException.LOAN_CHARGE_CANNOT_BE_PAYED_REASON;
-import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeUpdatedException;
 import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeUpdatedException.LOAN_CHARGE_CANNOT_BE_UPDATED_REASON;
-import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeWaivedException;
 import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeWaivedException.LOAN_CHARGE_CANNOT_BE_WAIVED_REASON;
-import org.apache.fineract.portfolio.charge.exception.LoanChargeNotFoundException;
 import org.apache.fineract.portfolio.client.domain.Client;
 import org.apache.fineract.portfolio.client.exception.ClientNotActiveException;
 import org.apache.fineract.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand;
@@ -115,44 +86,9 @@ import org.apache.fineract.portfolio.group.domain.Group;
 import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
 import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
 import org.apache.fineract.portfolio.loanaccount.command.LoanUpdateCommand;
-import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
-import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
-import org.apache.fineract.portfolio.loanaccount.data.LoanChargePaidByData;
-import org.apache.fineract.portfolio.loanaccount.data.LoanInstallmentChargeData;
-import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
-import org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail;
-import org.apache.fineract.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine;
-import org.apache.fineract.portfolio.loanaccount.domain.Loan;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeRepository;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanEvent;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanInstallmentCharge;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanOverdueInstallmentCharge;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanSubStatus;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanTrancheDisbursementCharge;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
-import org.apache.fineract.portfolio.loanaccount.exception.DateMismatchException;
-import org.apache.fineract.portfolio.loanaccount.exception.ExceedingTrancheCountException;
-import org.apache.fineract.portfolio.loanaccount.exception.InvalidPaidInAdvanceAmountException;
-import org.apache.fineract.portfolio.loanaccount.exception.LoanDisbursalException;
-import org.apache.fineract.portfolio.loanaccount.exception.LoanForeclosureException;
-import org.apache.fineract.portfolio.loanaccount.exception.LoanMultiDisbursementException;
-import org.apache.fineract.portfolio.loanaccount.exception.LoanOfficerAssignmentException;
-import org.apache.fineract.portfolio.loanaccount.exception.LoanOfficerUnassignmentException;
-import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionNotFoundException;
-import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementDataRequiredException;
+import org.apache.fineract.portfolio.loanaccount.data.*;
+import org.apache.fineract.portfolio.loanaccount.domain.*;
+import org.apache.fineract.portfolio.loanaccount.exception.*;
 import org.apache.fineract.portfolio.loanaccount.guarantor.service.GuarantorDomainService;
 import org.apache.fineract.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData;
 import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator;
@@ -231,6 +167,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
     private final GuarantorDomainService guarantorDomainService;
     private final LoanUtilService loanUtilService;
     private final LoanSummaryWrapper loanSummaryWrapper;
+    private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
     private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy;
     private final CodeValueRepositoryWrapper codeValueRepository;
 
@@ -260,6 +197,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
             final AccountTransferDetailRepository accountTransferDetailRepository,
             final BusinessEventNotifierService businessEventNotifierService, final GuarantorDomainService guarantorDomainService,
             final LoanUtilService loanUtilService, final LoanSummaryWrapper loanSummaryWrapper,
+            final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService,
             final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy,
             final CodeValueRepositoryWrapper codeValueRepository,
             final LoanRepositoryWrapper loanRepositoryWrapper) {
@@ -299,6 +237,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
         this.loanUtilService = loanUtilService;
         this.loanSummaryWrapper = loanSummaryWrapper;
         this.transactionProcessingStrategy = transactionProcessingStrategy;
+        this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService;
         this.codeValueRepository = codeValueRepository;
     }
 
@@ -318,7 +257,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
         final Loan loan = this.loanAssembler.assembleFrom(loanId);
         
         final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate");
-        
         // validate ActualDisbursement Date Against Expected Disbursement Date
         LoanProduct loanProduct = loan.loanProduct();
         if(loanProduct.syncExpectedWithDisbursementDate()){
@@ -329,6 +267,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
         final LocalDate nextPossibleRepaymentDate = loan.getNextPossibleRepaymentDateForRescheduling();
         final Date rescheduledRepaymentDate = command.DateValueOfParameterNamed("adjustRepaymentDate");
 
+        entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(),
+                StatusEnum.ACTIVATE.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId());
+
         // check for product mix validations
         checkForProductMixRestrictions(loan);
         
@@ -1114,6 +1055,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
         checkClientOrGroupActive(loan);
         this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.LOAN_WRITTEN_OFF,
                 constructEntityMap(BUSINESS_ENTITY.LOAN, loan));
+        entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(),
+                StatusEnum.WRITE_OFF.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId());
+
         removeLoanCycle(loan);
 
         final List<Long> existingTransactionIds = new ArrayList<>();

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java
index 883f9ad..6efa899 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java
@@ -167,6 +167,8 @@ public class SavingsApiConstants {
     public static final String daysToInactiveParamName = "daysToInactive";
     public static final String daysToDormancyParamName = "daysToDormancy";
     public static final String daysToEscheatParamName = "daysToEscheat";
+
+    public static final String datatables = "datatables";
     
 
     public static final Set<String> SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName,
@@ -220,7 +222,7 @@ public class SavingsApiConstants {
             // withdrawalFeeAmountParamName, withdrawalFeeTypeParamName,
             withdrawalFeeForTransfersParamName, feeAmountParamName, feeOnMonthDayParamName, chargesParamName, allowOverdraftParamName,
             overdraftLimitParamName, minRequiredBalanceParamName, enforceMinRequiredBalanceParamName,
-            nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName, withHoldTaxParamName));
+            nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName, withHoldTaxParamName,datatables));
 
     /**
      * These parameters will match the class level parameters of
@@ -236,7 +238,7 @@ public class SavingsApiConstants {
             feeOnMonthDayParamName, "summary", "transactions", "productOptions", "interestCompoundingPeriodTypeOptions",
             "interestPostingPeriodTypeOptions", "interestCalculationTypeOptions", "interestCalculationDaysInYearTypeOptions",
             "lockinPeriodFrequencyTypeOptions", "withdrawalFeeTypeOptions", "withdrawalFee", "annualFee", onHoldFundsParamName,
-            nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName));
+            nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName, datatables));
 
     public static final Set<String> SAVINGS_ACCOUNT_TRANSACTION_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName,
             dateFormatParamName, transactionDateParamName, transactionAmountParamName, paymentTypeIdParamName,

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java
index fa6064d..d06bbe9 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java
@@ -21,10 +21,12 @@ package org.apache.fineract.portfolio.savings.data;
 import java.math.BigDecimal;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.List;
 
 import org.apache.commons.lang3.builder.EqualsBuilder;
 import org.apache.commons.lang3.builder.HashCodeBuilder;
 import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
 import org.apache.fineract.organisation.monetary.data.CurrencyData;
 import org.apache.fineract.organisation.staff.data.StaffData;
 import org.apache.fineract.portfolio.charge.data.ChargeData;
@@ -100,6 +102,8 @@ public class SavingsAccountData {
     private final BigDecimal nominalAnnualInterestRateOverdraft;
     private final BigDecimal minOverdraftForInterestCalculation;
 
+    private List<DatatableData> datatables = null;
+
     public static SavingsAccountData instance(final Long id, final String accountNo, final EnumOptionData depositType,
             final String externalId, final Long groupId, final String groupName, final Long clientId, final String clientName,
             final Long productId, final String productName, final Long fieldOfficerId, final String fieldOfficerName,
@@ -557,4 +561,8 @@ public class SavingsAccountData {
     public Collection<SavingsAccountChargeData> charges() {
         return (this.charges == null) ? new HashSet<SavingsAccountChargeData>() : this.charges;
     }
+
+    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/savings/data/SavingsAccountDataValidator.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountDataValidator.java
index 586ef25..4cc6e89 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountDataValidator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountDataValidator.java
@@ -212,6 +212,11 @@ public class SavingsAccountDataValidator {
             baseDataValidator.reset().parameter(withHoldTaxParamName).value(withHoldTax).ignoreIfNull().validateForBooleanValue();
         }
 
+        if(this.fromApiJsonHelper.parameterExists(SavingsApiConstants.datatables, element)){
+            final JsonArray datatables = this.fromApiJsonHelper.extractJsonArrayNamed(SavingsApiConstants.datatables, element);
+            baseDataValidator.reset().parameter(SavingsApiConstants.datatables).value(datatables).notNull().jsonArrayNotEmpty();
+        }
+
         validateSavingsCharges(element, baseDataValidator);
 
         validateOverdraftParams(baseDataValidator, element);

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
index 38099d1..c912811 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
@@ -34,6 +34,10 @@ import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.core.service.PaginationHelper;
 import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
+import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
+import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
+import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.organisation.monetary.data.CurrencyData;
 import org.apache.fineract.organisation.monetary.domain.Money;
@@ -102,12 +106,15 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
     // pagination
     private final PaginationHelper<SavingsAccountData> paginationHelper = new PaginationHelper<>();
 
+    private final EntityDatatableChecksReadService entityDatatableChecksReadService;
+
     @Autowired
     public SavingsAccountReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
             final ClientReadPlatformService clientReadPlatformService, final GroupReadPlatformService groupReadPlatformService,
             final SavingsProductReadPlatformService savingProductReadPlatformService,
             final StaffReadPlatformService staffReadPlatformService, final SavingsDropdownReadPlatformService dropdownReadPlatformService,
-            final ChargeReadPlatformService chargeReadPlatformService) {
+            final ChargeReadPlatformService chargeReadPlatformService,
+            final EntityDatatableChecksReadService entityDatatableChecksReadService) {
         this.context = context;
         this.jdbcTemplate = new JdbcTemplate(dataSource);
         this.clientReadPlatformService = clientReadPlatformService;
@@ -120,6 +127,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
         this.savingAccountMapper = new SavingAccountMapper();
         // this.annualFeeMapper = new SavingsAccountAnnualFeeMapper();
         this.chargeReadPlatformService = chargeReadPlatformService;
+        this.entityDatatableChecksReadService = entityDatatableChecksReadService;
     }
 
     @Override
@@ -687,6 +695,10 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
                     charges, chargeOptions);
         }
 
+        final List<DatatableData> datatableTemplates = this.entityDatatableChecksReadService
+                .retrieveTemplates(StatusEnum.CREATE.getCode().longValue(), EntityTables.SAVING.getName(), productId);
+        template.setDatatables(datatableTemplates);
+
         return template;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
index 5d882c4..2064f57 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java
@@ -18,25 +18,11 @@
  */
 package org.apache.fineract.portfolio.savings.service;
 
-import static org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_CHARGE_RESOURCE_NAME;
-import static org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
-import static org.apache.fineract.portfolio.savings.SavingsApiConstants.amountParamName;
-import static org.apache.fineract.portfolio.savings.SavingsApiConstants.chargeIdParamName;
-import static org.apache.fineract.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName;
-import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withHoldTaxParamName;
-import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawBalanceParamName;
+import static org.apache.fineract.portfolio.savings.SavingsApiConstants.*;
 
 import java.math.BigDecimal;
 import java.math.MathContext;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
@@ -49,13 +35,12 @@ import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
 import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
 import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavailableException;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
+import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
+import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.organisation.holiday.domain.HolidayRepositoryWrapper;
-import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
-import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
-import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
-import org.apache.fineract.organisation.monetary.domain.Money;
-import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
+import org.apache.fineract.organisation.monetary.domain.*;
 import org.apache.fineract.organisation.office.domain.Office;
 import org.apache.fineract.organisation.staff.domain.Staff;
 import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper;
@@ -87,25 +72,9 @@ import org.apache.fineract.portfolio.savings.data.SavingsAccountChargeDataValida
 import org.apache.fineract.portfolio.savings.data.SavingsAccountDataValidator;
 import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionDTO;
 import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionDataValidator;
-import org.apache.fineract.portfolio.savings.domain.DepositAccountOnHoldTransaction;
-import org.apache.fineract.portfolio.savings.domain.DepositAccountOnHoldTransactionRepository;
-import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
-import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
-import org.apache.fineract.portfolio.savings.domain.SavingsAccountCharge;
-import org.apache.fineract.portfolio.savings.domain.SavingsAccountChargeRepositoryWrapper;
-import org.apache.fineract.portfolio.savings.domain.SavingsAccountDomainService;
-import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrapper;
-import org.apache.fineract.portfolio.savings.domain.SavingsAccountStatusType;
-import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
-import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionRepository;
-import org.apache.fineract.portfolio.savings.exception.PostInterestAsOnDateException;
+import org.apache.fineract.portfolio.savings.domain.*;
+import org.apache.fineract.portfolio.savings.exception.*;
 import org.apache.fineract.portfolio.savings.exception.PostInterestAsOnDateException.PostInterestAsOnException_TYPE;
-import org.apache.fineract.portfolio.savings.exception.PostInterestClosingDateException;
-import org.apache.fineract.portfolio.savings.exception.SavingsAccountClosingNotAllowedException;
-import org.apache.fineract.portfolio.savings.exception.SavingsAccountTransactionNotFoundException;
-import org.apache.fineract.portfolio.savings.exception.SavingsOfficerAssignmentException;
-import org.apache.fineract.portfolio.savings.exception.SavingsOfficerUnassignmentException;
-import org.apache.fineract.portfolio.savings.exception.TransactionUpdateNotAllowedException;
 import org.apache.fineract.useradministration.domain.AppUser;
 import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper;
 import org.joda.time.LocalDate;
@@ -140,6 +109,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
     private final WorkingDaysRepositoryWrapper workingDaysRepository;
     private final ConfigurationDomainService configurationDomainService;
     private final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository;
+    private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
     private final AppUserRepositoryWrapper appuserRepository;
     private final StandingInstructionRepository standingInstructionRepository;
     private final BusinessEventNotifierService businessEventNotifierService;
@@ -162,6 +132,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
             final SavingsAccountDataValidator fromApiJsonDeserializer, 
             final StaffRepositoryWrapper staffRepository, final ConfigurationDomainService configurationDomainService,
             final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository,
+            final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService, 
             final AppUserRepositoryWrapper appuserRepository, 
             final StandingInstructionRepository standingInstructionRepository, 
             final BusinessEventNotifierService businessEventNotifierService) {
@@ -186,6 +157,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
         this.staffRepository = staffRepository;
         this.configurationDomainService = configurationDomainService;
         this.depositAccountOnHoldTransactionRepository = depositAccountOnHoldTransactionRepository;
+        this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService;
         this.appuserRepository = appuserRepository;
         this.standingInstructionRepository = standingInstructionRepository;
         this.businessEventNotifierService = businessEventNotifierService;
@@ -205,6 +177,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
         final Set<Long> existingReversedTransactionIds = new HashSet<>();
         updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
         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()) {
             final Locale locale = command.extractLocale();
             final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
@@ -643,8 +620,10 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
                     + " is not allowed, since it is linked with one of the active accounts";
             throw new SavingsAccountClosingNotAllowedException("linked", defaultUserMessage, savingsId);
         }
-        
-       
+
+        entityDatatableChecksWritePlatformService.runTheCheckForProduct(savingsId, EntityTables.SAVING.getName(),
+                StatusEnum.CLOSE.getCode().longValue(),EntityTables.SAVING.getForeignKeyColumnNameOnDatatable(),
+                account.productId());
 
         final boolean isWithdrawBalance = command.booleanPrimitiveValueOfParameterNamed(withdrawBalanceParamName);
 

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java
index 35b94f5..45056ca 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java
@@ -20,13 +20,7 @@ package org.apache.fineract.portfolio.savings.service;
 
 import static org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 import javax.persistence.PersistenceException;
 
@@ -46,6 +40,9 @@ import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
 import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
 import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
+import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
+import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.organisation.monetary.domain.Money;
 import org.apache.fineract.organisation.staff.domain.Staff;
@@ -67,14 +64,7 @@ import org.apache.fineract.portfolio.note.domain.NoteRepository;
 import org.apache.fineract.portfolio.savings.SavingsApiConstants;
 import org.apache.fineract.portfolio.savings.data.SavingsAccountDataDTO;
 import org.apache.fineract.portfolio.savings.data.SavingsAccountDataValidator;
-import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
-import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
-import org.apache.fineract.portfolio.savings.domain.SavingsAccountCharge;
-import org.apache.fineract.portfolio.savings.domain.SavingsAccountChargeAssembler;
-import org.apache.fineract.portfolio.savings.domain.SavingsAccountDomainService;
-import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrapper;
-import org.apache.fineract.portfolio.savings.domain.SavingsProduct;
-import org.apache.fineract.portfolio.savings.domain.SavingsProductRepository;
+import org.apache.fineract.portfolio.savings.domain.*;
 import org.apache.fineract.portfolio.savings.exception.SavingsProductNotFoundException;
 import org.apache.fineract.useradministration.domain.AppUser;
 import org.slf4j.Logger;
@@ -106,7 +96,8 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
     private final SavingsAccountWritePlatformService savingsAccountWritePlatformService;
     private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository;
     private final BusinessEventNotifierService businessEventNotifierService;
-    
+    private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
+	
     @Autowired
     public SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
             final SavingsAccountRepositoryWrapper savingAccountRepository, final SavingsAccountAssembler savingAccountAssembler,
@@ -119,7 +110,8 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
             final SavingsAccountDomainService savingsAccountDomainService,
             final SavingsAccountWritePlatformService savingsAccountWritePlatformService,
             final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository,
-            final BusinessEventNotifierService businessEventNotifierService) {
+            final BusinessEventNotifierService businessEventNotifierService,
+            final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService) {
         this.context = context;
         this.savingAccountRepository = savingAccountRepository;
         this.savingAccountAssembler = savingAccountAssembler;
@@ -137,6 +129,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
         this.accountNumberFormatRepository = accountNumberFormatRepository;
         this.savingsAccountWritePlatformService = savingsAccountWritePlatformService;
         this.businessEventNotifierService = businessEventNotifierService ;
+        this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService;
     }
 
     /*
@@ -179,6 +172,15 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
             generateAccountNumber(account);
 
             final Long savingsId = account.getId();
+            if(command.parameterExists(SavingsApiConstants.datatables)){
+                this.entityDatatableChecksWritePlatformService.saveDatatables(StatusEnum.CREATE.getCode().longValue(),
+                        EntityTables.SAVING.getName(), savingsId, account.productId(),
+                        command.arrayOfParameterNamed(SavingsApiConstants.datatables));
+            }
+            this.entityDatatableChecksWritePlatformService.runTheCheckForProduct(savingsId,
+                    EntityTables.SAVING.getName(), StatusEnum.CREATE.getCode().longValue(),
+                    EntityTables.SAVING.getForeignKeyColumnNameOnDatatable(), account.productId());
+
             return new CommandProcessingResultBuilder() //
                     .withCommandId(command.commandId()) //
                     .withEntityId(savingsId) //
@@ -343,6 +345,11 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
         final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId);
         checkClientOrGroupActive(savingsAccount);
 
+        entityDatatableChecksWritePlatformService.runTheCheckForProduct(savingsId, EntityTables.SAVING.getName(),
+                StatusEnum.APPROVE.getCode().longValue(),EntityTables.SAVING.getForeignKeyColumnNameOnDatatable(),
+                savingsAccount.productId());
+
+
         final Map<String, Object> changes = savingsAccount.approveApplication(currentUser, command, DateUtils.getLocalDateOfTenant());
         if (!changes.isEmpty()) {
             this.savingAccountRepository.save(savingsAccount);
@@ -411,6 +418,10 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
         final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId);
         checkClientOrGroupActive(savingsAccount);
 
+        entityDatatableChecksWritePlatformService.runTheCheckForProduct(savingsId, EntityTables.SAVING.getName(),
+                StatusEnum.REJECTED.getCode().longValue(),EntityTables.SAVING.getForeignKeyColumnNameOnDatatable(),
+                savingsAccount.productId());
+
         final Map<String, Object> changes = savingsAccount.rejectApplication(currentUser, command, DateUtils.getLocalDateOfTenant());
         if (!changes.isEmpty()) {
             this.savingAccountRepository.save(savingsAccount);
@@ -445,6 +456,10 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
         final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId);
         checkClientOrGroupActive(savingsAccount);
 
+        entityDatatableChecksWritePlatformService.runTheCheckForProduct(savingsId, EntityTables.SAVING.getName(),
+                StatusEnum.WITHDRAWN.getCode().longValue(),EntityTables.SAVING.getForeignKeyColumnNameOnDatatable(),
+                savingsAccount.productId());
+
         final Map<String, Object> changes = savingsAccount.applicantWithdrawsFromApplication(currentUser, command,
                 DateUtils.getLocalDateOfTenant());
         if (!changes.isEmpty()) {

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/resources/sql/migrations/core_db/V324__datatable_checks.sql
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/resources/sql/migrations/core_db/V324__datatable_checks.sql b/fineract-provider/src/main/resources/sql/migrations/core_db/V324__datatable_checks.sql
new file mode 100644
index 0000000..6ba0658
--- /dev/null
+++ b/fineract-provider/src/main/resources/sql/migrations/core_db/V324__datatable_checks.sql
@@ -0,0 +1,46 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+CREATE TABLE `m_entity_datatable_check` (
+	`id` INT(11) NOT NULL AUTO_INCREMENT,
+	`application_table_name` VARCHAR(200) NOT NULL,
+	`x_registered_table_name` VARCHAR(50) NOT NULL,
+	`status_enum` INT(11) NOT NULL,
+	`system_defined` TINYINT(4) NOT NULL DEFAULT '0',
+	`product_id` BIGINT(10) NULL DEFAULT NULL,
+	PRIMARY KEY (`id`),
+	UNIQUE INDEX `unique_entity_check` (`application_table_name`, `x_registered_table_name`, `status_enum`, `product_id`),
+	INDEX `x_registered_table_name` (`x_registered_table_name`),
+	INDEX `product_id` (`product_id`),
+	CONSTRAINT `m_entity_datatable_check_ibfk_1` FOREIGN KEY (`x_registered_table_name`)
+	    REFERENCES `x_registered_table` (`registered_table_name`)
+)
+COLLATE='utf8_general_ci'
+ENGINE=InnoDB
+;
+
+
+INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
+VALUE ("datatable","READ_ENTITY_DATATABLE_CHECK","ENTITY_DATATABLE_CHECK","READ",0);
+
+INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
+VALUE ("datatable","CREATE_ENTITY_DATATABLE_CHECK","ENTITY_DATATABLE_CHECK","CREATE",0);
+
+INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
+VALUE ("datatable","DELETE_ENTITY_DATATABLE_CHECK","ENTITY_DATATABLE_CHECK","DELETE",0);


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

Posted by ra...@apache.org.
Entity datatable check implementation


Project: http://git-wip-us.apache.org/repos/asf/incubator-fineract/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-fineract/commit/dde6eaec
Tree: http://git-wip-us.apache.org/repos/asf/incubator-fineract/tree/dde6eaec
Diff: http://git-wip-us.apache.org/repos/asf/incubator-fineract/diff/dde6eaec

Branch: refs/heads/develop
Commit: dde6eaec2acc8031f7e1ee0fba65907bbaeee7b4
Parents: b60779b
Author: Satish <sa...@confluxtechnologies.com>
Authored: Thu Dec 8 09:48:28 2016 +0530
Committer: Satish <sa...@confluxtechnologies.com>
Committed: Thu Dec 8 09:48:28 2016 +0530

----------------------------------------------------------------------
 .../commands/service/CommandWrapperBuilder.java |  18 ++
 .../core/data/DataValidatorBuilder.java         |  20 ++
 .../api/EntityDatatableChecksApiResource.java   | 125 ++++++++
 .../data/DatatableCheckStatusData.java          |  31 ++
 .../dataqueries/data/DatatableChecksData.java   |  33 ++
 .../dataqueries/data/DatatableData.java         |  15 +
 .../data/EntityDataTableChecksData.java         |  51 +++
 .../data/EntityDataTableChecksTemplateData.java |  56 ++++
 .../dataqueries/data/EntityTables.java          | 108 +++++++
 .../dataqueries/data/StatusEnum.java            | 103 ++++++
 .../domain/EntityDatatableChecks.java           | 102 ++++++
 .../domain/EntityDatatableChecksRepository.java |  54 ++++
 .../DatatabaleEntryRequiredException.java       |  45 +++
 ...ityDatatableCheckAlreadyExistsException.java |  43 +++
 .../EntityDatatableCheckNotAllowException.java  |  35 +++
 ...tityDatatableCheckNotSupportedException.java |  39 +++
 .../EntityDatatableChecksNotFoundException.java |  32 ++
 ...eateEntityDatatableChecksCommandHandler.java |  48 +++
 ...leteEntityDatatableChecksCommandHandler.java |  48 +++
 .../EntityDatatableChecksDataValidator.java     |  98 ++++++
 ...yDatatableChecksReadPlatformServiceImpl.java | 217 +++++++++++++
 .../EntityDatatableChecksReadService.java       |  37 +++
 ...tityDatatableChecksWritePlatformService.java |  34 ++
 ...DatatableChecksWritePlatformServiceImpl.java | 315 +++++++++++++++++++
 .../service/ReadWriteNonCoreDataService.java    |   3 +
 .../ReadWriteNonCoreDataServiceImpl.java        |  64 ++--
 .../client/api/ClientApiConstants.java          |   6 +-
 .../portfolio/client/data/ClientData.java       |  29 +-
 .../client/data/ClientDataValidator.java        |  25 +-
 .../service/ClientReadPlatformServiceImpl.java  |  16 +-
 ...ntWritePlatformServiceJpaRepositoryImpl.java |  45 +--
 .../portfolio/group/api/CentersApiResource.java |  18 +-
 .../group/api/GroupingTypesApiConstants.java    |  12 +-
 .../portfolio/group/api/GroupsApiResource.java  |  14 +-
 .../portfolio/group/data/CenterData.java        |   8 +
 .../portfolio/group/data/GroupGeneralData.java  |   8 +
 .../GroupingTypesDataValidator.java             |  16 +
 ...esWritePlatformServiceJpaRepositoryImpl.java |  55 ++--
 .../loanaccount/api/LoanApiConstants.java       |   1 +
 .../loanaccount/api/LoansApiResource.java       |  23 +-
 .../loanaccount/data/LoanAccountData.java       |  12 +-
 ...LoanApplicationCommandFromApiJsonHelper.java |   8 +-
 ...onWritePlatformServiceJpaRepositoryImpl.java |  71 ++---
 ...anWritePlatformServiceJpaRepositoryImpl.java |  94 ++----
 .../portfolio/savings/SavingsApiConstants.java  |   6 +-
 .../savings/data/SavingsAccountData.java        |   8 +
 .../data/SavingsAccountDataValidator.java       |   5 +
 .../SavingsAccountReadPlatformServiceImpl.java  |  14 +-
 ...ntWritePlatformServiceJpaRepositoryImpl.java |  61 ++--
 ...ssWritePlatformServiceJpaRepositoryImpl.java |  49 ++-
 .../core_db/V324__datatable_checks.sql          |  46 +++
 51 files changed, 2134 insertions(+), 290 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java b/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
index 0cdc7e2..2ad6b22 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
@@ -2756,6 +2756,24 @@ public class CommandWrapperBuilder {
         return this;
     }
 
+    public CommandWrapperBuilder createEntityDatatableChecks(final String json) {
+        this.actionName = "CREATE";
+        this.entityName = "ENTITY_DATATABLE_CHECK";
+        this.entityId = null;
+        this.href = "/entityDatatableChecks/";
+        this.json = json;
+        return this;
+    }
+
+    public CommandWrapperBuilder deleteEntityDatatableChecks(final long entityDatatableCheckId, final String json) {
+        this.actionName = "DELETE";
+        this.entityName = "ENTITY_DATATABLE_CHECK";
+        this.entityId = entityDatatableCheckId;
+        this.href = "/entityDatatableChecks/" + entityDatatableCheckId;
+        this.json = json;
+        return this;
+    }
+
 	public CommandWrapperBuilder addSelfServiceBeneficiaryTPT() {
         this.actionName = "CREATE";
         this.entityName = "SSBENEFICIARYTPT";

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/data/DataValidatorBuilder.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/data/DataValidatorBuilder.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/data/DataValidatorBuilder.java
index e628619..def8d88 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/data/DataValidatorBuilder.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/data/DataValidatorBuilder.java
@@ -278,6 +278,26 @@ public class DataValidatorBuilder {
         return this;
     }
 
+    public DataValidatorBuilder isOneOfTheseStringValues(final List<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) {
         if (this.value == null && this.ignoreNullValue) { return this; }
 

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/EntityDatatableChecksApiResource.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/EntityDatatableChecksApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/EntityDatatableChecksApiResource.java
new file mode 100644
index 0000000..8806874
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/EntityDatatableChecksApiResource.java
@@ -0,0 +1,125 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.api;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.fineract.commands.domain.CommandWrapper;
+import org.apache.fineract.commands.service.CommandWrapperBuilder;
+import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
+import org.apache.fineract.infrastructure.core.api.ApiParameterHelper;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer;
+import org.apache.fineract.infrastructure.core.service.Page;
+import org.apache.fineract.infrastructure.core.service.SearchParameters;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityDataTableChecksData;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityDataTableChecksTemplateData;
+import org.apache.fineract.infrastructure.dataqueries.data.GenericResultsetData;
+import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService;
+import org.apache.fineract.infrastructure.dataqueries.service.GenericDataService;
+import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+@Path("/entityDatatableChecks")
+@Component
+@Scope("singleton")
+public class EntityDatatableChecksApiResource {
+
+    private final PlatformSecurityContext context;
+    private final GenericDataService genericDataService;
+    private final EntityDatatableChecksReadService readEntityDatatableChecksService;
+    private final ToApiJsonSerializer<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);
+    }
+
+}
\ 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/data/DatatableCheckStatusData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableCheckStatusData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableCheckStatusData.java
new file mode 100644
index 0000000..43f0047
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableCheckStatusData.java
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.data;
+
+public class DatatableCheckStatusData {
+
+	private final String name;
+	private final int code;
+
+	public DatatableCheckStatusData(final String name, final int code) {
+		this.name = name;
+		this.code = code;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableChecksData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableChecksData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableChecksData.java
new file mode 100644
index 0000000..361e847
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableChecksData.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.data;
+
+import java.io.Serializable;
+
+public class DatatableChecksData implements Serializable {
+
+	private static final long serialVersionUID = 3113568562509206452L;
+	private final String entity;
+	private final String dataTableName;
+
+	public DatatableChecksData(final String entity, final String dataTableName) {
+		this.entity = entity;
+		this.dataTableName = dataTableName;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableData.java
index f23b8ff..42491d0 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/DatatableData.java
@@ -45,4 +45,19 @@ public class DatatableData {
         this.columnHeaderData = columnHeaderData;
 
     }
+
+    public boolean hasColumn(final String columnName){
+
+        for(ResultsetColumnHeaderData c : this.columnHeaderData){
+
+            if(c.getColumnName().equals(columnName)) return true;
+        }
+
+        return false;
+    }
+
+    public String getRegisteredTableName(){
+        return registeredTableName;
+    }
+    
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityDataTableChecksData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityDataTableChecksData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityDataTableChecksData.java
new file mode 100644
index 0000000..0a6482f
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityDataTableChecksData.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.data;
+
+import java.io.Serializable;
+
+import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+
+/**
+ * Immutable data object for role data.
+ */
+public class EntityDataTableChecksData implements Serializable {
+
+    private final long id;
+    private final String entity;
+    private final EnumOptionData status;
+    private final String datatableName;
+    private final boolean systemDefined;
+    private final Long order;
+    private final Long productId;
+    private final String productName;
+
+    public EntityDataTableChecksData(final long id, final String entity, final EnumOptionData status, final String datatableName,
+            final boolean systemDefined, final Long loanProductId, final String productName) {
+        this.id = id;
+        this.entity = entity;
+        this.status = status;
+        this.datatableName = datatableName;
+        this.systemDefined = systemDefined;
+        this.order = id;
+        this.productId = loanProductId;
+        this.productName = productName;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityDataTableChecksTemplateData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityDataTableChecksTemplateData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityDataTableChecksTemplateData.java
new file mode 100644
index 0000000..962c08d
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityDataTableChecksTemplateData.java
@@ -0,0 +1,56 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.data;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.fineract.portfolio.loanproduct.data.LoanProductData;
+import org.apache.fineract.portfolio.savings.data.SavingsProductData;
+
+/**
+ * Immutable data object for role data.
+ */
+public class EntityDataTableChecksTemplateData implements Serializable {
+
+	private final List<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;
+	}
+}
\ 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/data/EntityTables.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityTables.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityTables.java
new file mode 100644
index 0000000..51f77c3
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/EntityTables.java
@@ -0,0 +1,108 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.data;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public enum EntityTables {
+
+	CLIENT("m_client",
+        new Integer[]{StatusEnum.CREATE.getCode(),
+                StatusEnum.ACTIVATE.getCode(),
+                StatusEnum.CLOSE.getCode()},
+        "client_id"),
+    LOAN("m_loan",
+        new Integer[]{StatusEnum.CREATE.getCode(),
+                StatusEnum.APPROVE.getCode(),
+                StatusEnum.ACTIVATE.getCode(),
+                StatusEnum.WITHDRAWN.getCode(),
+                StatusEnum.REJECTED.getCode(),
+                StatusEnum.WRITE_OFF.getCode()},
+        "loan_id"),
+    GROUP("m_group",
+        new Integer[]{StatusEnum.CREATE.getCode(),
+                StatusEnum.ACTIVATE.getCode(),
+                StatusEnum.CLOSE.getCode(),},
+        "group_id"),
+    SAVING("m_savings_account",
+        new Integer[]{StatusEnum.CREATE.getCode(),
+                StatusEnum.APPROVE.getCode(),
+                StatusEnum.ACTIVATE.getCode(),
+                StatusEnum.WITHDRAWN.getCode(),
+                StatusEnum.REJECTED.getCode(),
+                StatusEnum.CLOSE.getCode()},
+        "savings_account_id");
+
+	private static final Map<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;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/StatusEnum.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/StatusEnum.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/StatusEnum.java
new file mode 100644
index 0000000..4700e28
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/data/StatusEnum.java
@@ -0,0 +1,103 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+
+public enum StatusEnum {
+
+    CREATE("create", 100), APPROVE("approve", 200), ACTIVATE("activate", 300), WITHDRAWN("withdraw", 400), REJECTED("reject", 500), CLOSE(
+            "close", 600), WRITE_OFF("write off", 601), RESCHEDULE("reschedule", 602), OVERPAY("overpay", 700);
+
+    private String name;
+
+    public Integer getCode() {
+        return code;
+    }
+
+    private Integer code;
+
+    private StatusEnum(String name, Integer code) {
+
+        this.name = name;
+        this.code = code;
+
+    }
+
+    public static List<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;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/EntityDatatableChecks.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/EntityDatatableChecks.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/EntityDatatableChecks.java
new file mode 100644
index 0000000..9aef5b6
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/EntityDatatableChecks.java
@@ -0,0 +1,102 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.domain;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
+
+@Entity
+@Table(name = "m_entity_datatable_check")
+
+public class EntityDatatableChecks extends AbstractPersistableCustom<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;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/EntityDatatableChecksRepository.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/EntityDatatableChecksRepository.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/EntityDatatableChecksRepository.java
new file mode 100644
index 0000000..0560f8f
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/EntityDatatableChecksRepository.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.domain;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+public interface EntityDatatableChecksRepository
+		extends
+			JpaRepository<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);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/DatatabaleEntryRequiredException.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/DatatabaleEntryRequiredException.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/DatatabaleEntryRequiredException.java
new file mode 100644
index 0000000..7885d34
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/DatatabaleEntryRequiredException.java
@@ -0,0 +1,45 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.exception;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.fineract.infrastructure.core.data.ApiParameterError;
+import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
+
+/**
+ * A {@link RuntimeException} thrown when datatable resources are not found.
+ */
+public class DatatabaleEntryRequiredException extends RuntimeException {
+
+	public DatatabaleEntryRequiredException(final String datatableName) {
+
+		final List<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);
+	}
+
+}
\ 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/exception/EntityDatatableCheckAlreadyExistsException.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckAlreadyExistsException.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckAlreadyExistsException.java
new file mode 100644
index 0000000..e941f05
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckAlreadyExistsException.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.exception;
+
+import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
+
+/**
+ * A {@link RuntimeException} thrown when datatable resources are not found.
+ */
+public class EntityDatatableCheckAlreadyExistsException extends AbstractPlatformDomainRuleException {
+
+	public EntityDatatableCheckAlreadyExistsException(final String entityName, final Long status,
+			final String datatableName) {
+		super("error.msg.entityDatatableCheck.duplicate.entry",
+				"the entity datatable check for status: '" + status + "' and datatable name '" + datatableName
+				+ "' on entity '" + entityName + "' already exist",
+				"status", "datatableName", "entity", status, datatableName, entityName);
+	}
+
+	public EntityDatatableCheckAlreadyExistsException(final String entityName, long status, String datatableName,
+			long productId) {
+		super("error.msg.entityDatatableCheck.duplicate.entry",
+				"the entity datatable check for status: '" + status + "' and datatable name '" + datatableName
+                + "' on entity '" + entityName + "' and product id '" + productId + "' already exist",
+				"status", "datatableName", "entity", "productId", status, datatableName, entityName, productId);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckNotAllowException.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckNotAllowException.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckNotAllowException.java
new file mode 100644
index 0000000..e04153c
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckNotAllowException.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.exception;
+
+import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
+
+/**
+ * A {@link RuntimeException} thrown when datatable resources are not found.
+ */
+public class EntityDatatableCheckNotAllowException extends AbstractPlatformResourceNotFoundException {
+
+	public EntityDatatableCheckNotAllowException(final String entityName) {
+		super("error.msg.entity.datatable.check.is.not.allowed",
+				"Entity Datatable check is not allow without a loan product id to :entity,"
+						+ " because there is already a check attached to the same entity with a loan product id",
+				entityName);
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckNotSupportedException.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckNotSupportedException.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckNotSupportedException.java
new file mode 100644
index 0000000..5380099
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableCheckNotSupportedException.java
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.exception;
+
+import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
+
+/**
+ * A {@link RuntimeException} thrown when datatable resources are not found.
+ */
+public class EntityDatatableCheckNotSupportedException extends AbstractPlatformResourceNotFoundException {
+
+	public EntityDatatableCheckNotSupportedException(final String datatableName, final String entityName) {
+		super("error.msg.entity.datatable.check.combination.not.supported",
+				"Entity Datatable check on table "+datatableName+" is not supported for entity "+entityName, datatableName,
+				entityName);
+	}
+
+	public EntityDatatableCheckNotSupportedException(final String entityName, final Long productId) {
+		super("error.msg.entity.datatable.check.combination.not.supported",
+				"Entity Datatable check on entity "+entityName+" is not supported with productId "+productId, entityName,
+				productId);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableChecksNotFoundException.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableChecksNotFoundException.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableChecksNotFoundException.java
new file mode 100644
index 0000000..0e61617
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/EntityDatatableChecksNotFoundException.java
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.exception;
+
+import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
+
+/**
+ * A {@link RuntimeException} thrown when report resources are not found.
+ */
+public class EntityDatatableChecksNotFoundException extends AbstractPlatformResourceNotFoundException {
+
+	public EntityDatatableChecksNotFoundException(final Long id) {
+		super("error.msg.entity.datatable.check.not.found",
+				"Entity datatable check with identifier " + id + " does not exist", id);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/handler/CreateEntityDatatableChecksCommandHandler.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/handler/CreateEntityDatatableChecksCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/handler/CreateEntityDatatableChecksCommandHandler.java
new file mode 100644
index 0000000..e7caed1
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/handler/CreateEntityDatatableChecksCommandHandler.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.handler;
+
+import org.apache.fineract.commands.annotation.CommandType;
+import org.apache.fineract.commands.handler.NewCommandSourceHandler;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@CommandType(entity = "ENTITY_DATATABLE_CHECK", action = "CREATE")
+public class CreateEntityDatatableChecksCommandHandler implements NewCommandSourceHandler {
+
+	private final EntityDatatableChecksWritePlatformService writePlatformService;
+
+	@Autowired
+	public CreateEntityDatatableChecksCommandHandler(
+			final EntityDatatableChecksWritePlatformService writePlatformService) {
+		this.writePlatformService = writePlatformService;
+	}
+
+	@Transactional
+	@Override
+	public CommandProcessingResult processCommand(final JsonCommand command) {
+
+		return this.writePlatformService.createCheck(command);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/handler/DeleteEntityDatatableChecksCommandHandler.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/handler/DeleteEntityDatatableChecksCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/handler/DeleteEntityDatatableChecksCommandHandler.java
new file mode 100644
index 0000000..f430171
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/handler/DeleteEntityDatatableChecksCommandHandler.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.handler;
+
+import org.apache.fineract.commands.annotation.CommandType;
+import org.apache.fineract.commands.handler.NewCommandSourceHandler;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@CommandType(entity = "ENTITY_DATATABLE_CHECK", action = "DELETE")
+public class DeleteEntityDatatableChecksCommandHandler implements NewCommandSourceHandler {
+
+	private final EntityDatatableChecksWritePlatformService writePlatformService;
+
+	@Autowired
+	public DeleteEntityDatatableChecksCommandHandler(
+			final EntityDatatableChecksWritePlatformService writePlatformService) {
+		this.writePlatformService = writePlatformService;
+	}
+
+	@Transactional
+	@Override
+	public CommandProcessingResult processCommand(JsonCommand command) {
+
+		return this.writePlatformService.deleteCheck(command.entityId());
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/dde6eaec/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksDataValidator.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksDataValidator.java
new file mode 100644
index 0000000..81b54be
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksDataValidator.java
@@ -0,0 +1,98 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.service;
+
+import java.lang.reflect.Type;
+import java.util.*;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.fineract.infrastructure.core.data.ApiParameterError;
+import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
+import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
+import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
+import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.google.gson.JsonElement;
+import com.google.gson.reflect.TypeToken;
+
+@Component
+public final class EntityDatatableChecksDataValidator {
+
+	/**
+	 * The parameters supported for this command.
+	 */
+	private final Set<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);
+		}
+	}
+}
\ 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/EntityDatatableChecksReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadPlatformServiceImpl.java
new file mode 100644
index 0000000..31f58a2
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadPlatformServiceImpl.java
@@ -0,0 +1,217 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.service;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
+import org.apache.fineract.infrastructure.core.service.Page;
+import org.apache.fineract.infrastructure.core.service.PaginationHelper;
+import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
+import org.apache.fineract.infrastructure.core.service.SearchParameters;
+import org.apache.fineract.infrastructure.dataqueries.data.DatatableCheckStatusData;
+import org.apache.fineract.infrastructure.dataqueries.data.DatatableChecksData;
+import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityDataTableChecksData;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityDataTableChecksTemplateData;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
+import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
+import org.apache.fineract.infrastructure.dataqueries.domain.EntityDatatableChecks;
+import org.apache.fineract.infrastructure.dataqueries.domain.EntityDatatableChecksRepository;
+import org.apache.fineract.portfolio.loanproduct.data.LoanProductData;
+import org.apache.fineract.portfolio.loanproduct.service.LoanProductReadPlatformService;
+import org.apache.fineract.portfolio.savings.data.SavingsProductData;
+import org.apache.fineract.portfolio.savings.service.SavingsProductReadPlatformService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.stereotype.Service;
+
+@Service
+public class EntityDatatableChecksReadPlatformServiceImpl implements EntityDatatableChecksReadService {
+
+    private final JdbcTemplate jdbcTemplate;
+    private final RegisterDataTableMapper registerDataTableMapper;
+    private final EntityDataTableChecksMapper entityDataTableChecksMapper;
+    private final EntityDatatableChecksRepository entityDatatableChecksRepository;
+    private final ReadWriteNonCoreDataService readWriteNonCoreDataService;
+    private final LoanProductReadPlatformService loanProductReadPlatformService;
+    private final SavingsProductReadPlatformService savingsProductReadPlatformService;
+    private final PaginationHelper<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' ";
+        }
+    }
+
+}
\ 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/EntityDatatableChecksReadService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadService.java
new file mode 100644
index 0000000..3b1b029
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadService.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.service;
+
+import java.util.List;
+
+import org.apache.fineract.infrastructure.core.service.Page;
+import org.apache.fineract.infrastructure.core.service.SearchParameters;
+import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityDataTableChecksData;
+import org.apache.fineract.infrastructure.dataqueries.data.EntityDataTableChecksTemplateData;
+
+public interface EntityDatatableChecksReadService {
+
+    EntityDataTableChecksTemplateData retrieveTemplate();
+
+    List<DatatableData> retrieveTemplates(Long status, String entity, Long productId);
+
+    Page<EntityDataTableChecksData> retrieveAll(SearchParameters searchParameters, Long status, String entity, Long productLoanId);
+
+}
\ 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/EntityDatatableChecksWritePlatformService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksWritePlatformService.java
new file mode 100644
index 0000000..d20b48e
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksWritePlatformService.java
@@ -0,0 +1,34 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.dataqueries.service;
+
+import com.google.gson.JsonArray;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+
+public interface EntityDatatableChecksWritePlatformService {
+
+	CommandProcessingResult createCheck(JsonCommand command);
+	CommandProcessingResult deleteCheck(final Long entityDatatableCheckId);
+	void runTheCheck(final Long entityId, final String entityName, final Long statusCode, String foreignKeyColumn);
+	void runTheCheckForProduct(final Long entityId, final String entityName, final Long statusCode,
+			String foreignKeyColumn, long productLoanId);
+	boolean saveDatatables(Long status, String entity, Long entityId, Long productId, JsonArray data);
+
+}
\ No newline at end of file


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

Posted by ra...@apache.org.
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);
     }



[5/5] incubator-fineract git commit: Merge branch 'AmazonS3ImageFix' into develop

Posted by ra...@apache.org.
Merge branch 'AmazonS3ImageFix' into develop


Project: http://git-wip-us.apache.org/repos/asf/incubator-fineract/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-fineract/commit/09629933
Tree: http://git-wip-us.apache.org/repos/asf/incubator-fineract/tree/09629933
Diff: http://git-wip-us.apache.org/repos/asf/incubator-fineract/diff/09629933

Branch: refs/heads/develop
Commit: 09629933e1d1c1f8f0cb3c701dc4068add4772f5
Parents: dde6eae 628fb30
Author: Adi Narayana Raju <ad...@confluxtechnologies.com>
Authored: Fri Dec 9 16:38:56 2016 +0530
Committer: Adi Narayana Raju <ad...@confluxtechnologies.com>
Committed: Fri Dec 9 16:38:56 2016 +0530

----------------------------------------------------------------------
 .../contentrepository/S3ContentRepository.java  |  9 +-
 .../documentmanagement/data/ImageData.java      | 86 +++++++++++++++-----
 .../service/ImageReadPlatformServiceImpl.java   |  4 +-
 3 files changed, 76 insertions(+), 23 deletions(-)
----------------------------------------------------------------------



[4/5] incubator-fineract git commit: FINERACT-288 - Client's Image Uploaded Not Showing on UI in Amazon S3

Posted by ra...@apache.org.
FINERACT-288 - Client's Image Uploaded Not Showing on UI in Amazon S3


Project: http://git-wip-us.apache.org/repos/asf/incubator-fineract/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-fineract/commit/628fb303
Tree: http://git-wip-us.apache.org/repos/asf/incubator-fineract/tree/628fb303
Diff: http://git-wip-us.apache.org/repos/asf/incubator-fineract/diff/628fb303

Branch: refs/heads/develop
Commit: 628fb30347898e5051b297598c69a628eec4152a
Parents: b60779b
Author: Nazeer Hussain Shaik <na...@confluxtechnologies.com>
Authored: Fri Dec 9 16:07:35 2016 +0530
Committer: Nazeer Hussain Shaik <na...@confluxtechnologies.com>
Committed: Fri Dec 9 16:07:35 2016 +0530

----------------------------------------------------------------------
 .../contentrepository/S3ContentRepository.java  |  9 +-
 .../documentmanagement/data/ImageData.java      | 86 +++++++++++++++-----
 .../service/ImageReadPlatformServiceImpl.java   |  4 +-
 3 files changed, 76 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/628fb303/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/contentrepository/S3ContentRepository.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/contentrepository/S3ContentRepository.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/contentrepository/S3ContentRepository.java
index ce7cd5e..28109fe 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/contentrepository/S3ContentRepository.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/contentrepository/S3ContentRepository.java
@@ -38,6 +38,7 @@ import com.amazonaws.AmazonServiceException;
 import com.amazonaws.auth.BasicAWSCredentials;
 import com.amazonaws.services.s3.AmazonS3;
 import com.amazonaws.services.s3.AmazonS3Client;
+import com.amazonaws.services.s3.model.AmazonS3Exception;
 import com.amazonaws.services.s3.model.DeleteObjectRequest;
 import com.amazonaws.services.s3.model.GetObjectRequest;
 import com.amazonaws.services.s3.model.ObjectMetadata;
@@ -134,8 +135,12 @@ public class S3ContentRepository implements ContentRepository {
 
     @Override
     public ImageData fetchImage(final ImageData imageData) {
-        final S3Object s3object = this.s3Client.getObject(new GetObjectRequest(this.s3BucketName, imageData.location()));
-        imageData.updateContent(s3object.getObjectContent());
+    	try {
+    		final S3Object s3object = this.s3Client.getObject(new GetObjectRequest(this.s3BucketName, imageData.location()));
+            imageData.updateContent(s3object.getObjectContent());	
+    	}catch(AmazonS3Exception e) {
+    		logger.error(e.getMessage());
+    	}
         return imageData;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/628fb303/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/data/ImageData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/data/ImageData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/data/ImageData.java
index a0373d1..3196efc 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/data/ImageData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/data/ImageData.java
@@ -25,6 +25,7 @@ import java.awt.image.BufferedImage;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -35,9 +36,13 @@ import org.apache.commons.lang.StringUtils;
 import org.apache.fineract.infrastructure.documentmanagement.contentrepository.ContentRepositoryUtils;
 import org.apache.fineract.infrastructure.documentmanagement.domain.StorageType;
 import org.apache.poi.util.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class ImageData {
 
+    private final static Logger logger = LoggerFactory.getLogger(ImageData.class);
+
     @SuppressWarnings("unused")
     private final Long imageId;
     private final String location;
@@ -56,17 +61,17 @@ public class ImageData {
     }
 
     public byte[] getContent() {
-        // TODO Vishwas Fix error handling
         try {
-            if (this.inputStream == null) {
+            if (this.storageType.equals(StorageType.S3.getValue()) && this.inputStream != null) {
+                return IOUtils.toByteArray(this.inputStream);
+            } else if (this.storageType.equals(StorageType.FILE_SYSTEM.getValue()) && this.file != null) {
                 final FileInputStream fileInputStream = new FileInputStream(this.file);
                 return IOUtils.toByteArray(fileInputStream);
             }
-
-            return IOUtils.toByteArray(this.inputStream);
-        } catch (final IOException e) {
-            return null;
+        } catch (IOException e) {
+            logger.error(e.getMessage());
         }
+        return null;
     }
 
     public byte[] resizeImage(InputStream in, int maxWidth, int maxHeight) throws IOException {
@@ -102,22 +107,33 @@ public class ImageData {
     }
 
     public byte[] getContentOfSize(Integer maxWidth, Integer maxHeight) {
-        if (maxWidth == null && maxHeight == null) { return getContent(); }
-        FileInputStream fis = null;
-        try {
-            fis = new FileInputStream(this.file);
-            byte[] out = resizeImage(fis, maxWidth != null ? maxWidth : Integer.MAX_VALUE, maxHeight != null ? maxHeight
-                    : Integer.MAX_VALUE);
-            return out;
-        } catch (IOException ex) {
-            return null;
-        } finally {
-            if (fis != null) {
-                try {
-                    fis.close();
-                } catch (IOException ex) {}
+        if (maxWidth == null && maxHeight != null) { return getContent(); }
+        byte[] out = null;
+        if (this.storageType.equals(StorageType.S3.getValue()) && this.inputStream != null) {
+            try {
+                out = resizeImage(this.inputStream, maxWidth != null ? maxWidth : Integer.MAX_VALUE,
+                        maxHeight != null ? maxHeight : Integer.MAX_VALUE);
+            } catch (IOException e) {
+                logger.error(e.getMessage());
+            }
+        } else if (this.storageType.equals(StorageType.FILE_SYSTEM.getValue()) && this.file != null) {
+            FileInputStream fis = null;
+            try {
+                fis = new FileInputStream(this.file);
+                out = resizeImage(fis, maxWidth != null ? maxWidth : Integer.MAX_VALUE, maxHeight != null ? maxHeight : Integer.MAX_VALUE);
+            } catch (IOException ex) {
+                logger.error(ex.getMessage());
+            } finally {
+                if (fis != null) {
+                    try {
+                        fis.close();
+                    } catch (IOException ex) {
+                        logger.error(ex.getMessage());
+                    }
+                }
             }
         }
+        return out;
     }
 
     private void setImageContentType(String filename) {
@@ -161,4 +177,34 @@ public class ImageData {
         return this.entityDisplayName;
     }
 
+    public boolean available() {
+        int available = -1; // not -1
+        if (this.storageType.equals(StorageType.S3.getValue()) && this.inputStream != null) {
+            try {
+                available = this.inputStream.available();
+            } catch (IOException e) {
+                logger.error(e.getMessage());
+            }
+        } else if (this.storageType.equals(StorageType.FILE_SYSTEM.getValue()) && this.file != null) {
+            FileInputStream fileInputStream = null;
+            try {
+                fileInputStream = new FileInputStream(this.file);
+                available = fileInputStream.available();
+                fileInputStream.close();
+            } catch (FileNotFoundException e) {
+                logger.error(e.getMessage());
+            } catch (IOException e) {
+                logger.error(e.getMessage());
+            } finally {
+                if (fileInputStream != null) {
+                    try {
+                        fileInputStream.close();
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        }
+        return available >= 0;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/628fb303/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/service/ImageReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/service/ImageReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/service/ImageReadPlatformServiceImpl.java
index 9348268..c62fc91 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/service/ImageReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/service/ImageReadPlatformServiceImpl.java
@@ -103,7 +103,9 @@ public class ImageReadPlatformServiceImpl implements ImageReadPlatformService {
             final ContentRepository contentRepository = this.contentRepositoryFactory.getRepository(imageData.storageType());
             final ImageData result = contentRepository.fetchImage(imageData);
 
-            if (result.getContent() == null) { throw new ImageNotFoundException(entityType, entityId); }
+          //Once we read content EofSensorInputStream, the wrappedStream object is becoming null. So further image source is becoming null 
+            //For Amazon S3. If file is not present, already S3ContentRepository would have thrown this exception.
+            if (!result.available()) { throw new ImageNotFoundException(entityType, entityId); }
 
             return result;
         } catch (final EmptyResultDataAccessException e) {