Repository: incubator-fineract Updated Branches: refs/heads/develop 94baf15b9 -> 8b20f0818
Fixed issue with entity datatable check Project: http://git-wip-us.apache.org/repos/asf/incubator-fineract/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-fineract/commit/8b20f081 Tree: http://git-wip-us.apache.org/repos/asf/incubator-fineract/tree/8b20f081 Diff: http://git-wip-us.apache.org/repos/asf/incubator-fineract/diff/8b20f081 Branch: refs/heads/develop Commit: 8b20f0818c2f6b5c32f568c19715954a82cd35de Parents: 94baf15 Author: Satish <satish.saj...@confluxtechnologies.com> Authored: Fri Dec 16 17:07:35 2016 +0530 Committer: Satish <satish.saj...@confluxtechnologies.com> Committed: Mon Dec 19 09:45:57 2016 +0530 ---------------------------------------------------------------------- .../dataqueries/data/EntityTables.java | 2 +- .../dataqueries/data/StatusEnum.java | 5 +- .../DatatabaleEntryRequiredException.java | 32 -- .../DatatableEntryRequiredException.java | 38 ++ ...DatatableChecksWritePlatformServiceImpl.java | 493 +++++++++---------- .../ReadWriteNonCoreDataServiceImpl.java | 14 +- .../client/domain/ClientRepositoryWrapper.java | 4 + ...ntWritePlatformServiceJpaRepositoryImpl.java | 64 ++- .../group/domain/GroupRepositoryWrapper.java | 4 + ...esWritePlatformServiceJpaRepositoryImpl.java | 35 +- ...anWritePlatformServiceJpaRepositoryImpl.java | 2 +- 11 files changed, 367 insertions(+), 326 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/8b20f081/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 index 51f77c3..349670e 100644 --- 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 @@ -33,7 +33,7 @@ public enum EntityTables { LOAN("m_loan", new Integer[]{StatusEnum.CREATE.getCode(), StatusEnum.APPROVE.getCode(), - StatusEnum.ACTIVATE.getCode(), + StatusEnum.DISBURSE.getCode(), StatusEnum.WITHDRAWN.getCode(), StatusEnum.REJECTED.getCode(), StatusEnum.WRITE_OFF.getCode()}, http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/8b20f081/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 index 4700e28..45ade5c 100644 --- 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 @@ -26,7 +26,7 @@ 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); + "close", 600), WRITE_OFF("write off", 601), RESCHEDULE("reschedule", 602), OVERPAY("overpay", 700), DISBURSE("disburse", 800); private String name; @@ -85,6 +85,9 @@ public enum StatusEnum { case 700: ret = StatusEnum.OVERPAY; break; + case 800: + ret = StatusEnum.DISBURSE; + break; default: break; } http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/8b20f081/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 deleted file mode 100644 index 87402e4..0000000 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/DatatabaleEntryRequiredException.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * 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 AbstractPlatformDomainRuleException} thrown when datatable resources are not found. - */ -public class DatatabaleEntryRequiredException extends AbstractPlatformDomainRuleException{ - - public DatatabaleEntryRequiredException(String datatableName) { - super("error.msg.entry.required.in.datatable." + datatableName, "The datatable " + datatableName - + " needs to be filled in before the current action can be proceeded", datatableName); - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/8b20f081/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/DatatableEntryRequiredException.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/DatatableEntryRequiredException.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/DatatableEntryRequiredException.java new file mode 100644 index 0000000..c774fe7 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/exception/DatatableEntryRequiredException.java @@ -0,0 +1,38 @@ +/** + * 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 AbstractPlatformDomainRuleException} thrown when datatable resources are not found. + */ +public class DatatableEntryRequiredException extends AbstractPlatformDomainRuleException { + + public DatatableEntryRequiredException(String datatableName) { + super("error.msg.entry.required.in.datatable." + datatableName, "The datatable " + datatableName + + " needs to be filled in before the current action can be proceeded", datatableName); + } + + public DatatableEntryRequiredException(String datatableName, Long appTableId) { + super("error.msg.entry.cannot.be.deleted.datatable." + datatableName + ".attached.to.entity.datatable.check", + "The entry cannot be deleted, due to datatable " + datatableName + " is attached to an Entity-Datatable check", + datatableName, appTableId); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/8b20f081/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 index 34f1312..3046dfa 100644 --- 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 @@ -55,261 +55,242 @@ 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()); - } + 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(); + } + } + + @Override + 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 DatatableEntryRequiredException(reqDatatables.toString()); } + } + + } + + @Override + 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 DatatableEntryRequiredException(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/8b20f081/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 e0a0696..0bcb144 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 @@ -45,6 +45,7 @@ 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.*; +import org.apache.fineract.infrastructure.dataqueries.exception.DatatableEntryRequiredException; import org.apache.fineract.infrastructure.dataqueries.exception.DatatableNotFoundException; import org.apache.fineract.infrastructure.dataqueries.exception.DatatableSystemErrorException; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; @@ -1121,9 +1122,9 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ @Override public CommandProcessingResult deleteDatatableEntries(final String dataTableName, final Long appTableId) { + if (isDatatableAttachedToEntityDatatableCheck(dataTableName)) { throw new DatatableEntryRequiredException(dataTableName, appTableId); } final String appTable = queryForApplicationTableName(dataTableName); final CommandProcessingResult commandProcessingResult = checkMainResourceExistsWithinScope(appTable, appTableId); - final String deleteOneToOneEntrySql = getDeleteEntriesSql(dataTableName, getFKField(appTable), appTableId); final int rowsDeleted = this.jdbcTemplate.update(deleteOneToOneEntrySql); @@ -1135,7 +1136,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ @Transactional @Override public CommandProcessingResult deleteDatatableEntry(final String dataTableName, final Long appTableId, final Long datatableId) { - + if (isDatatableAttachedToEntityDatatableCheck(dataTableName)) { throw new DatatableEntryRequiredException(dataTableName, appTableId); } final String appTable = queryForApplicationTableName(dataTableName); final CommandProcessingResult commandProcessingResult = checkMainResourceExistsWithinScope(appTable, appTableId); @@ -1730,4 +1731,13 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ return count; } + public boolean isDatatableAttachedToEntityDatatableCheck(final String datatableName) { + StringBuilder builder = new StringBuilder(); + builder.append(" SELECT COUNT(edc.`x_registered_table_name`) FROM `x_registered_table` xrt "); + builder.append(" JOIN m_entity_datatable_check edc ON edc.`x_registered_table_name` = xrt.`registered_table_name`"); + builder.append(" WHERE edc.`x_registered_table_name` = '" + datatableName + "'"); + final Long count = this.jdbcTemplate.queryForObject(builder.toString(), Long.class); + return (count > 0) ? true : false; + } + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/8b20f081/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientRepositoryWrapper.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientRepositoryWrapper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientRepositoryWrapper.java index bdfccb9..f4231d1 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientRepositoryWrapper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientRepositoryWrapper.java @@ -74,6 +74,10 @@ public class ClientRepositoryWrapper { public void delete(final Client client) { this.repository.delete(client); } + + public void flush() { + this.repository.flush(); + } public Client getActiveClientInUserScope(Long clientId) { final Client client = this.findOneWithNotFoundDetection(clientId); http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/8b20f081/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 d2fa74c..4941e3e 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,7 +18,11 @@ */ package org.apache.fineract.portfolio.client.service; -import java.util.*; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; import javax.persistence.PersistenceException; @@ -50,8 +54,18 @@ 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.*; -import org.apache.fineract.portfolio.client.exception.*; +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.common.BusinessEventNotificationConstants.BUSINESS_ENTITY; import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS; import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService; @@ -151,23 +165,29 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP @Transactional @Override public CommandProcessingResult deleteClient(final Long clientId) { + try { + final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId); - final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId); + if (client.isNotPending()) { throw new ClientMustBePendingToBeDeletedException(clientId); } + final List<Note> relatedNotes = this.noteRepository.findByClientId(clientId); + this.noteRepository.deleteInBatch(relatedNotes); - if (client.isNotPending()) { throw new ClientMustBePendingToBeDeletedException(clientId); } - final List<Note> relatedNotes = this.noteRepository.findByClientId(clientId); - this.noteRepository.deleteInBatch(relatedNotes); + final ClientNonPerson clientNonPerson = this.clientNonPersonRepository.findOneByClientId(clientId); + if (clientNonPerson != null) this.clientNonPersonRepository.delete(clientNonPerson); - final ClientNonPerson clientNonPerson = this.clientNonPersonRepository.findOneByClientId(clientId); - if(clientNonPerson != null) - this.clientNonPersonRepository.delete(clientNonPerson); - - this.clientRepository.delete(client); - return new CommandProcessingResultBuilder() // - .withOfficeId(client.officeId()) // - .withClientId(clientId) // - .withEntityId(clientId) // - .build(); + this.clientRepository.delete(client); + this.clientRepository.flush(); + return new CommandProcessingResultBuilder() // + .withOfficeId(client.officeId()) // + .withClientId(clientId) // + .withEntityId(clientId) // + .build(); + } catch (DataIntegrityViolationException dve) { + Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ; + logger.error(throwable.getMessage()); + throw new PlatformDataIntegrityException("error.msg.client.unknown.data.integrity.issue", + "Unknown data integrity issue with resource."); + } } /* @@ -270,9 +290,11 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP final Client newClient = Client.createNew(currentUser, clientOffice, clientParentGroup, staff, savingsProductId, gender, clientType, clientClassification, legalFormValue, command); + this.clientRepository.save(newClient); boolean rollbackTransaction = false; if (newClient.isActive()) { validateParentGroupRulesBeforeClientActivation(newClient); + runEntityDatatableCheck(newClient.getId()); final CommandWrapper commandWrapper = new CommandWrapperBuilder().activateClient(null).build(); rollbackTransaction = this.commandProcessingService.validateCommand(commandWrapper, currentUser); } @@ -533,8 +555,7 @@ 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()); + runEntityDatatableCheck(clientId); final AppUser currentUser = this.context.authenticatedUser(); client.activate(currentUser, fmt, activationDate); @@ -766,6 +787,11 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP } } + private void runEntityDatatableCheck(final Long clientId) { + entityDatatableChecksWritePlatformService.runTheCheck(clientId, EntityTables.CLIENT.getName(), StatusEnum.ACTIVATE.getCode() + .longValue(), EntityTables.CLIENT.getForeignKeyColumnNameOnDatatable()); + } + @Override public CommandProcessingResult rejectClient(final Long entityId, final JsonCommand command) { final AppUser currentUser = this.context.authenticatedUser(); http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/8b20f081/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/domain/GroupRepositoryWrapper.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/domain/GroupRepositoryWrapper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/domain/GroupRepositoryWrapper.java index a67b90e..c863913 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/domain/GroupRepositoryWrapper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/domain/GroupRepositoryWrapper.java @@ -62,4 +62,8 @@ public class GroupRepositoryWrapper { public void delete(final Group entity) { this.repository.delete(entity); } + + public void flush() { + this.repository.flush(); + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/8b20f081/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 19b4a41..f485af8 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 @@ -174,6 +174,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group boolean rollbackTransaction = false; if (newGroup.isActive()) { + this.groupRepository.save(newGroup); // validate Group creation rules for Group if (newGroup.isGroup()) { validateGroupRulesBeforeActivation(newGroup); @@ -295,9 +296,6 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group 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); @@ -323,6 +321,8 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group Integer maxClients = configurationDomainService.retrieveMaxAllowedClientsInGroup(); boolean isGroupClientCountValid = group.isGroupsClientCountWithinMinMaxRange(minClients, maxClients); if (!isGroupClientCountValid) { throw new GroupMemberCountNotInPermissibleRangeException(group.getId(), minClients, maxClients); } + entityDatatableChecksWritePlatformService.runTheCheck(group.getId(), EntityTables.GROUP.getName(), + StatusEnum.ACTIVATE.getCode().longValue(), EntityTables.GROUP.getForeignKeyColumnNameOnDatatable()); } public void validateGroupRulesBeforeClientAssociation(final Group group) { @@ -549,21 +549,28 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group @Transactional @Override public CommandProcessingResult deleteGroup(final Long groupId) { + try { - final Group groupForDelete = this.groupRepository.findOneWithNotFoundDetection(groupId); - - if (groupForDelete.isNotPending()) { throw new GroupMustBePendingToBeDeletedException(groupId); } + final Group groupForDelete = this.groupRepository.findOneWithNotFoundDetection(groupId); - final List<Note> relatedNotes = this.noteRepository.findByGroupId(groupId); - this.noteRepository.deleteInBatch(relatedNotes); + if (groupForDelete.isNotPending()) { throw new GroupMustBePendingToBeDeletedException(groupId); } - this.groupRepository.delete(groupForDelete); + final List<Note> relatedNotes = this.noteRepository.findByGroupId(groupId); + this.noteRepository.deleteInBatch(relatedNotes); - return new CommandProcessingResultBuilder() // - .withOfficeId(groupForDelete.getId()) // - .withGroupId(groupForDelete.officeId()) // - .withEntityId(groupForDelete.getId()) // - .build(); + this.groupRepository.delete(groupForDelete); + this.groupRepository.flush(); + return new CommandProcessingResultBuilder() // + .withOfficeId(groupForDelete.getId()) // + .withGroupId(groupForDelete.officeId()) // + .withEntityId(groupForDelete.getId()) // + .build(); + } catch (DataIntegrityViolationException dve) { + Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()); + logger.error(throwable.getMessage()); + throw new PlatformDataIntegrityException("error.msg.group.unknown.data.integrity.issue", + "Unknown data integrity issue with resource."); + } } @Override http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/8b20f081/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 95b4c94..38afb87 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 @@ -268,7 +268,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final Date rescheduledRepaymentDate = command.DateValueOfParameterNamed("adjustRepaymentDate"); entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(), - StatusEnum.ACTIVATE.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId()); + StatusEnum.DISBURSE.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId()); // check for product mix validations checkForProductMixRestrictions(loan);