From 9d11434ee7ee20f97bbfdb7e2ac170976ec01360 Mon Sep 17 00:00:00 2001 From: Binny G Sreevas Date: Sat, 6 Dec 2014 14:16:28 +0530 Subject: [PATCH] Branch Specific Products and Charges - initial commit --- .../codes/data/CodeValueData.java | 4 + .../codes/domain/CodeValueRepository.java | 2 + .../domain/CodeValueRepositoryWrapper.java | 7 + .../exception/CodeValueNotFoundException.java | 5 + .../MifosEntityAccessConstants.java | 35 +++ .../data/MifosEntityAccessData.java | 33 +++ .../entityaccess/domain/MifosEntity.java | 23 ++ .../domain/MifosEntityAccess.java | 152 +++++++++++ .../domain/MifosEntityAccessRepository.java | 13 + .../MifosEntityAccessRepositoryWrapper.java | 46 ++++ .../domain/MifosEntityAccessType.java | 33 +++ .../entityaccess/domain/MifosEntityType.java | 47 ++++ ...fosEntityAccessConfigurationException.java | 18 ++ .../MifosEntityAccessNotFoundException.java | 18 ++ .../service/MifosEntityAccessReadService.java | 27 ++ .../MifosEntityAccessReadServiceImpl.java | 251 ++++++++++++++++++ .../service/MifosEntityAccessUtil.java | 130 +++++++++ .../MifosEntityAccessWriteService.java | 30 +++ .../MifosEntityAccessWriteServiceImpl.java | 72 +++++ .../ChargeReadPlatformServiceImpl.java | 89 +++++-- ...WritePlatformServiceJpaRepositoryImpl.java | 24 +- .../LoanProductReadPlatformServiceImpl.java | 78 +++++- ...WritePlatformServiceJpaRepositoryImpl.java | 14 +- ...SavingsProductReadPlatformServiceImpl.java | 56 +++- ...WritePlatformServiceJpaRepositoryImpl.java | 16 +- .../core_db/V225__entity_to_entity_access.sql | 45 ++++ 26 files changed, 1230 insertions(+), 38 deletions(-) create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/MifosEntityAccessConstants.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/data/MifosEntityAccessData.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntity.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityAccess.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityAccessRepository.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityAccessRepositoryWrapper.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityAccessType.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityType.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/exception/MifosEntityAccessConfigurationException.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/exception/MifosEntityAccessNotFoundException.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessReadService.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessReadServiceImpl.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessUtil.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessWriteService.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessWriteServiceImpl.java create mode 100644 mifosng-provider/src/main/resources/sql/migrations/core_db/V225__entity_to_entity_access.sql diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/data/CodeValueData.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/data/CodeValueData.java index 9c0a1f1e9..9e8a42b4f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/data/CodeValueData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/data/CodeValueData.java @@ -53,4 +53,8 @@ public class CodeValueData implements Serializable { public Long getId() { return this.id; } + + public String getName() { + return this.name; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/domain/CodeValueRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/domain/CodeValueRepository.java index 8c2aefcf5..8c387e9c4 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/domain/CodeValueRepository.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/domain/CodeValueRepository.java @@ -11,4 +11,6 @@ import org.springframework.data.jpa.repository.JpaSpecificationExecutor; public interface CodeValueRepository extends JpaRepository, JpaSpecificationExecutor { CodeValue findByCodeNameAndId(String codeName, Long id); + + CodeValue findByCodeNameAndLabel (String codeName, String label); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/domain/CodeValueRepositoryWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/domain/CodeValueRepositoryWrapper.java index eb77da53f..c4cd17ed6 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/domain/CodeValueRepositoryWrapper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/domain/CodeValueRepositoryWrapper.java @@ -43,4 +43,11 @@ public class CodeValueRepositoryWrapper { if (codeValue == null) { throw new CodeValueNotFoundException(codeName, id); } return codeValue; } + + public CodeValue findOneByCodeNameAndLabelWithNotFoundDetection(final String codeName, final String label) { + final CodeValue codeValue = this.repository.findByCodeNameAndLabel(codeName, label); + if (codeValue == null) { throw new CodeValueNotFoundException(codeName, label); } + return codeValue; + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/exception/CodeValueNotFoundException.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/exception/CodeValueNotFoundException.java index 563a23cfe..bdf03e8be 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/exception/CodeValueNotFoundException.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/exception/CodeValueNotFoundException.java @@ -20,4 +20,9 @@ public class CodeValueNotFoundException extends AbstractPlatformResourceNotFound super("error.msg.codevalue.codename.id.combination.invalid", "Code value with identifier " + id + " does not exist for a code with name " + codeName, id, codeName); } + + public CodeValueNotFoundException(final String codeName, final String label) { + super("error.msg.codevalue.codename.id.combination.invalid", "Code value with label " + label + + " does not exist for a code with name " + codeName, label, codeName); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/MifosEntityAccessConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/MifosEntityAccessConstants.java new file mode 100644 index 000000000..ffe297f49 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/MifosEntityAccessConstants.java @@ -0,0 +1,35 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.infrastructure.entityaccess; + +public class MifosEntityAccessConstants { + + public static final String GLOBAL_CONFIG_FOR_OFFICE_SPECIFIC_PRODUCTS = "office-specific-products-enabled"; + public static final String GLOBAL_CONFIG_FOR_RESTRICT_PRODUCTS_TO_USER_OFFICE = "restrict-products-to-user-office"; + public static final String ENTITY_ACCESS_CODENAME = "Entity to Entity Access Types"; + + /*** + * Enum of all parameters passed in while creating/updating an entity access + ***/ + public static enum ENTITY_ACCESS_JSON_INPUT_PARAMS { + ENTITY_TYPE("entityType"), + ENTITY_ID("entityId"), + ENTITY_ACCESS_TYPE_ID("entityAccessTypeId"), + SECOND_ENTITY_TYPE("secondEntityType"), + SECOND_ENTITY_ID("secondEntityId") + ; + + private final String value; + + private ENTITY_ACCESS_JSON_INPUT_PARAMS(final String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/data/MifosEntityAccessData.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/data/MifosEntityAccessData.java new file mode 100644 index 000000000..0f88d4774 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/data/MifosEntityAccessData.java @@ -0,0 +1,33 @@ +package org.mifosplatform.infrastructure.entityaccess.data; + +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntity; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityAccessType; + +public class MifosEntityAccessData { + private MifosEntity firstEntity; + private MifosEntityAccessType accessType; + private MifosEntity secondEntity; + + public MifosEntityAccessData ( + MifosEntity firstEntity, + MifosEntityAccessType accessType, + MifosEntity secondEntity + ) { + this.firstEntity = firstEntity; + this.accessType = accessType; + this.secondEntity = secondEntity; + } + + public MifosEntity getFirstEntity() { + return this.firstEntity; + } + + public MifosEntityAccessType getAccessType() { + return this.accessType; + } + + public MifosEntity getSecondEntity() { + return this.secondEntity; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntity.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntity.java new file mode 100644 index 000000000..4d1ca0911 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntity.java @@ -0,0 +1,23 @@ +package org.mifosplatform.infrastructure.entityaccess.domain; + +public class MifosEntity { + private Long entityId; + private MifosEntityType type; + + @SuppressWarnings("unused") + private MifosEntity() { + } + + public MifosEntity(Long entityId, MifosEntityType type) { + this.entityId = entityId; + this.type = type; + } + + public Long getId () { + return this.entityId; + } + + public MifosEntityType getType () { + return this.type; + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityAccess.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityAccess.java new file mode 100644 index 000000000..837338955 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityAccess.java @@ -0,0 +1,152 @@ +package org.mifosplatform.infrastructure.entityaccess.domain; + +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +import java.util.LinkedHashMap; +import java.util.Map; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import org.mifosplatform.infrastructure.codes.domain.CodeValue; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.entityaccess.MifosEntityAccessConstants; +import org.springframework.data.jpa.domain.AbstractPersistable; + +@Entity +@Table(name = "m_entity_to_entity_access") +public class MifosEntityAccess extends AbstractPersistable { + + @Column(name = "entity_type", length = 50) + private String entityType; + + @Column(name = "entity_id") + private Long entityId; + + @ManyToOne + @JoinColumn(name = "access_type_code_value_id", nullable = false) + private CodeValue accessType; + + @Column(name = "second_entity_type", length = 50) + private String secondEntityType; + + @Column(name = "second_entity_id") + private Long secondEntityId; + + protected MifosEntityAccess () { + + } + + public static MifosEntityAccess createNew(final String entityType, final Long entityId, + final CodeValue accessType, + final String secondEntityType, final Long secondEntityId) { + return new MifosEntityAccess(entityType, entityId, accessType, + secondEntityType, secondEntityId); + } + + public MifosEntityAccess(final String entityType, final Long entityId, + final CodeValue accessType, + final String secondEntityType, final Long secondEntityId) { + this.entityType = entityType; + this.entityId = entityId; + this.accessType = accessType; + this.secondEntityType = secondEntityType; + this.secondEntityId = secondEntityId; + } + + public static MifosEntityAccess fromJson(final CodeValue accessType, final JsonCommand command) { + final String entityType = command.stringValueOfParameterNamed( + MifosEntityAccessConstants.ENTITY_ACCESS_JSON_INPUT_PARAMS.ENTITY_TYPE.getValue()); + final Long entityId = command.longValueOfParameterNamed( + MifosEntityAccessConstants.ENTITY_ACCESS_JSON_INPUT_PARAMS.ENTITY_ID.getValue()); + final String secondEntityType = command.stringValueOfParameterNamed( + MifosEntityAccessConstants.ENTITY_ACCESS_JSON_INPUT_PARAMS.SECOND_ENTITY_ID.getValue()); + final Long secondEntityId = command.longValueOfParameterNamed( + MifosEntityAccessConstants.ENTITY_ACCESS_JSON_INPUT_PARAMS.SECOND_ENTITY_ID.getValue()); + + return new MifosEntityAccess (entityType, entityId, accessType, + secondEntityType, secondEntityId); + + } + + public Map update(final JsonCommand command) { + + final Map actualChanges = new LinkedHashMap<>(); + + String paramName = null; + + paramName = MifosEntityAccessConstants.ENTITY_ACCESS_JSON_INPUT_PARAMS.ENTITY_TYPE.getValue(); + if (command.isChangeInStringParameterNamed(paramName, this.entityType)) { + final String newValue = command.stringValueOfParameterNamed(paramName); + actualChanges.put(paramName, newValue); + this.entityType = newValue; + } + + paramName = MifosEntityAccessConstants.ENTITY_ACCESS_JSON_INPUT_PARAMS.ENTITY_ID.getValue(); + if (command.isChangeInLongParameterNamed(paramName, getEntityId())) { + this.entityId = command.longValueOfParameterNamed(paramName); + actualChanges.put(paramName, this.entityId); + } + + Long existingAccessTypeId = null; + if (this.accessType != null) { + existingAccessTypeId = this.accessType.getId(); + } + + paramName = MifosEntityAccessConstants.ENTITY_ACCESS_JSON_INPUT_PARAMS.ENTITY_ACCESS_TYPE_ID.getValue(); + if (command.isChangeInLongParameterNamed(paramName, existingAccessTypeId)) { + final Long newValue = command.longValueOfParameterNamed(paramName); + actualChanges.put(paramName, newValue); + } + + paramName = MifosEntityAccessConstants.ENTITY_ACCESS_JSON_INPUT_PARAMS.SECOND_ENTITY_TYPE.getValue(); + if (command.isChangeInStringParameterNamed(paramName, this.secondEntityType)) { + final String newValue = command.stringValueOfParameterNamed(paramName); + actualChanges.put(paramName, newValue); + this.secondEntityType = newValue; + } + + paramName = MifosEntityAccessConstants.ENTITY_ACCESS_JSON_INPUT_PARAMS.SECOND_ENTITY_ID.getValue(); + if (command.isChangeInLongParameterNamed(paramName, getSecondEntityId())) { + this.secondEntityId = command.longValueOfParameterNamed(paramName); + actualChanges.put(paramName, this.secondEntityId); + } + + return actualChanges; + } + + public String getEntityType() { + return this.entityType; + } + + public Long getEntityId() { + return this.entityId; + } + + public CodeValue getAccessType() { + return this.accessType; + } + + public void updateAccessType(final CodeValue accessType) { + this.accessType = accessType; + } + + public String getSecondEntityType() { + return this.secondEntityType; + } + + public Long getSecondEntityId() { + return this.secondEntityId; + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityAccessRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityAccessRepository.java new file mode 100644 index 000000000..8c8b20312 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityAccessRepository.java @@ -0,0 +1,13 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.infrastructure.entityaccess.domain; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface MifosEntityAccessRepository extends JpaRepository, JpaSpecificationExecutor { + // no added behaviour +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityAccessRepositoryWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityAccessRepositoryWrapper.java new file mode 100644 index 000000000..e3a6a50d1 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityAccessRepositoryWrapper.java @@ -0,0 +1,46 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package org.mifosplatform.infrastructure.entityaccess.domain; + +import org.mifosplatform.infrastructure.entityaccess.exception.MifosEntityAccessNotFoundException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + *

+ * Wrapper for {@link MifosEntityAccessRepository} that adds NULL checking and Error + * handling capabilities + *

+ */ +@Service +public class MifosEntityAccessRepositoryWrapper { + + private final MifosEntityAccessRepository repository; + + @Autowired + public MifosEntityAccessRepositoryWrapper(final MifosEntityAccessRepository repository) { + this.repository = repository; + } + + public MifosEntityAccess findOneWithNotFoundDetection(final Long id) { + final MifosEntityAccess mifosEntityAccess = this.repository.findOne(id); + if (mifosEntityAccess == null) { throw new MifosEntityAccessNotFoundException(id); } + return mifosEntityAccess; + } + + public void save(final MifosEntityAccess mifosEntityAccess) { + this.repository.save(mifosEntityAccess); + } + + public void saveAndFlush(final MifosEntityAccess mifosEntityAccess) { + this.repository.saveAndFlush(mifosEntityAccess); + } + + public void delete(final MifosEntityAccess mifosEntityAccess) { + this.repository.delete(mifosEntityAccess); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityAccessType.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityAccessType.java new file mode 100644 index 000000000..ae8aef5dd --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityAccessType.java @@ -0,0 +1,33 @@ +package org.mifosplatform.infrastructure.entityaccess.domain; + +public class MifosEntityAccessType { + + private String str; + + public static final MifosEntityAccessType OFFICE_ACCESS_TO_LOAN_PRODUCTS = new MifosEntityAccessType("Office Access to Loan Products"); + public static final MifosEntityAccessType OFFICE_ACCESS_TO_SAVINGS_PRODUCTS = new MifosEntityAccessType("Office Access to Savings Products"); + public static final MifosEntityAccessType OFFICE_ACCESS_TO_CHARGES = new MifosEntityAccessType("Office Access to Fees/Charges"); + + private MifosEntityAccessType (String str) { + this.str = str; + } + + public String toStr () { + return this.str; + } + + public static MifosEntityAccessType get (String type) { + + MifosEntityAccessType retType = null; + + if (type.equals(OFFICE_ACCESS_TO_LOAN_PRODUCTS.str)) { + retType = OFFICE_ACCESS_TO_LOAN_PRODUCTS; + } else if (type.equals(OFFICE_ACCESS_TO_SAVINGS_PRODUCTS.str)) { + retType = OFFICE_ACCESS_TO_SAVINGS_PRODUCTS; + } else if (type.equals(OFFICE_ACCESS_TO_CHARGES.str)) { + retType = OFFICE_ACCESS_TO_CHARGES; + } + + return retType; + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityType.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityType.java new file mode 100644 index 000000000..092cbc716 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/domain/MifosEntityType.java @@ -0,0 +1,47 @@ +package org.mifosplatform.infrastructure.entityaccess.domain; + +public class MifosEntityType { + private String type; + private String description; + private String table_name; + + public static MifosEntityType OFFICE = new MifosEntityType ("office", "Offices", "m_office"); + public static MifosEntityType LOAN_PRODUCT = new MifosEntityType ("loan_product", "Loan Products", "m_product_loan"); + public static MifosEntityType SAVINGS_PRODUCT = new MifosEntityType ("savings_product", "Savings Products", "m_savings_product"); + public static MifosEntityType CHARGE = new MifosEntityType ("charge", "Fees/Charges", "m_charge"); + + private MifosEntityType (String type, String description, String table_name) { + this.type = type; + this.description = description; + this.table_name = table_name; + } + + public String getType () { + return this.type; + } + + public String getDescription () { + return this.description; + } + + public String getTable () { + return this.table_name; + } + + public static MifosEntityType get (String type) { + + MifosEntityType retType = null; + + if (type.equals(OFFICE.type)) { + retType = OFFICE; + } else if (type.equals(LOAN_PRODUCT.type)) { + retType = LOAN_PRODUCT; + } else if (type.equals(SAVINGS_PRODUCT)) { + retType = SAVINGS_PRODUCT; + } else if (type.equals(CHARGE)) + retType = CHARGE; + + return retType; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/exception/MifosEntityAccessConfigurationException.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/exception/MifosEntityAccessConfigurationException.java new file mode 100644 index 000000000..5cda70459 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/exception/MifosEntityAccessConfigurationException.java @@ -0,0 +1,18 @@ +package org.mifosplatform.infrastructure.entityaccess.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityAccessType; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityType; + +public class MifosEntityAccessConfigurationException extends AbstractPlatformDomainRuleException { + + public MifosEntityAccessConfigurationException(final Long firstEntityId, + final MifosEntityType entityType1, + final MifosEntityAccessType accessType, + final MifosEntityType entityType2) { + super("error.msg.entityaccess.config", + "Error while getting entity access configuration for " + entityType1.getType() + ":" + firstEntityId + + " with type " + accessType.toStr() + " against " + entityType2.getType()); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/exception/MifosEntityAccessNotFoundException.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/exception/MifosEntityAccessNotFoundException.java new file mode 100644 index 000000000..3871df3d6 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/exception/MifosEntityAccessNotFoundException.java @@ -0,0 +1,18 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.infrastructure.entityaccess.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; + +/** + * A {@link RuntimeException} thrown when office resources are not found. + */ +public class MifosEntityAccessNotFoundException extends AbstractPlatformResourceNotFoundException { + + public MifosEntityAccessNotFoundException(final Long id) { + super("error.msg.entityaccess.id.invalid", "MifosEntityAccess with identifier " + id + " does not exist", id); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessReadService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessReadService.java new file mode 100644 index 000000000..c1429c439 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessReadService.java @@ -0,0 +1,27 @@ +package org.mifosplatform.infrastructure.entityaccess.service; + +import java.util.Collection; + +import org.mifosplatform.infrastructure.entityaccess.data.MifosEntityAccessData; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityAccessType; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityType; + + +public interface MifosEntityAccessReadService { + Collection retrieveEntityAccessFor (Long entityId, MifosEntityType type, + MifosEntityAccessType accessType, MifosEntityType secondType, + boolean includeAllOffices); + + String getSQLQueryInClause_WithListOfIDsForEntityAccess (Long entityId, MifosEntityType firstEntityType, + MifosEntityAccessType accessType, MifosEntityType secondEntityType, + boolean includeAllOffices); + + String getSQLQueryInClauseIDList_ForLoanProductsForOffice (Long loanProductId, + boolean includeAllOffices); + + String getSQLQueryInClauseIDList_ForSavingsProductsForOffice( + Long savingsProductId, boolean includeAllOffices); + + String getSQLQueryInClauseIDList_ForChargesForOffice(Long officeId, + boolean includeAllOffices); +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessReadServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessReadServiceImpl.java new file mode 100644 index 000000000..35d78749a --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessReadServiceImpl.java @@ -0,0 +1,251 @@ +package org.mifosplatform.infrastructure.entityaccess.service; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; + +import javax.sql.DataSource; + +import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.domain.JdbcSupport; +import org.mifosplatform.infrastructure.core.service.RoutingDataSource; +import org.mifosplatform.infrastructure.dataqueries.service.GenericDataServiceImpl; +import org.mifosplatform.infrastructure.entityaccess.MifosEntityAccessConstants; +import org.mifosplatform.infrastructure.entityaccess.data.MifosEntityAccessData; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntity; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityAccessType; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityType; +import org.mifosplatform.infrastructure.entityaccess.exception.MifosEntityAccessConfigurationException; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; +import org.mifosplatform.organisation.office.data.OfficeData; +import org.mifosplatform.useradministration.domain.AppUser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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 MifosEntityAccessReadServiceImpl implements MifosEntityAccessReadService { + + private final PlatformSecurityContext context; + private final JdbcTemplate jdbcTemplate; + private final static Logger logger = LoggerFactory.getLogger(GenericDataServiceImpl.class); + + @Autowired + public MifosEntityAccessReadServiceImpl(final PlatformSecurityContext context, + final RoutingDataSource dataSource) { + this.context = context; + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + /* + * (non-Javadoc) + * @see org.mifosplatform.infrastructure.entityaccess.service.MifosEntityAccessReadService#getSQLQueryWithListOfIDsForEntityAccess + * (Long, + * org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityType, + * org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityAccessType, + * org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityType, + * boolean) + * + * This method returns the list of entity IDs as a comma separated list + * Or null if there is no entity restrictions or if there + */ + @Override + public String getSQLQueryInClause_WithListOfIDsForEntityAccess ( + Long firstEntityId, + MifosEntityType firstEntityType, + MifosEntityAccessType accessType, + MifosEntityType secondEntityType, + boolean includeAllOffices) { + Collection accesslist = retrieveEntityAccessFor ( + firstEntityId, firstEntityType, accessType, secondEntityType, includeAllOffices); + String returnIdListStr = null; + StringBuffer accessListCSVStrBuf = null; + if ( (accesslist != null) && (accesslist.size() > 0) ) { + logger.debug("Found " + accesslist.size() + + " access type restrictions while getting entity access configuration for " + + firstEntityType.getType() + ":" + firstEntityId + + " with type " + accessType.toStr() + " against " + secondEntityType.getType() + ); + accessListCSVStrBuf = new StringBuffer (" "); + for (int i = 0; i < accesslist.size(); i++) { + MifosEntityAccessData accessData = (MifosEntityAccessData) accesslist.toArray()[i]; + if (accessData == null) { + throw new MifosEntityAccessConfigurationException(firstEntityId, firstEntityType, + accessType, secondEntityType); + } + if (accessData.getSecondEntity().getId() == 0) { // If there is any ID that zero, then allow access to all + accessListCSVStrBuf = null; + break; + } + if (i>0) { + accessListCSVStrBuf.append(','); + } + accessListCSVStrBuf.append(accessData.getSecondEntity().getId()); + } + + } else { + logger.debug("Found zero access type restrictions while getting entity access configuration for " + + firstEntityType.getType() + ":" + firstEntityId + + " with type " + accessType.toStr() + " against " + secondEntityType.getType() + ); + accessListCSVStrBuf = new StringBuffer(); + accessListCSVStrBuf.append ("false"); // Append false so that no rows will be returned + } + if (accessListCSVStrBuf != null) { + returnIdListStr = accessListCSVStrBuf.toString(); + } + logger.debug("List of IDs applicable:" + returnIdListStr); + return returnIdListStr; + } + + @Override + public Collection retrieveEntityAccessFor( + Long firstEntityId, + MifosEntityType firstEntityType, + MifosEntityAccessType accessType, + MifosEntityType secondEntityType, + boolean includeAllSubOffices) { + final AppUser currentUser = this.context.authenticatedUser(); + + final String hierarchy = currentUser.getOffice().getHierarchy(); + String hierarchySearchString = null; + if (includeAllSubOffices) { + hierarchySearchString = "." + "%"; + } else { + hierarchySearchString = hierarchy + "%"; + } + String sql = getSQLForRetriveEntityAccessFor(firstEntityType, + accessType, secondEntityType); + + Collection entityAccessData = null; + MifosEntityAccessDataMapper mapper = new MifosEntityAccessDataMapper(); + + if (includeAllSubOffices && (firstEntityType.getTable().equals("m_office")) ) { + sql += " where firstentity.hierarchy like ? order by firstEntity.hierarchy"; + entityAccessData = this.jdbcTemplate.query(sql, mapper, new Object[] { firstEntityId, hierarchySearchString }); + } else { + entityAccessData = this.jdbcTemplate.query(sql, mapper, new Object[] { firstEntityId }); + } + + return entityAccessData; + } + + private String getSQLForRetriveEntityAccessFor ( + MifosEntityType firstEntityType, + MifosEntityAccessType accessType, + MifosEntityType secondEntityType) { + StringBuffer str = new StringBuffer ("select eea.entity_id as entity_id, entity_type as entity_type, "); + str.append("access_type_code_value_id as access_id, cv.code_value as access_type_desc, c.code_name as code, "); + str.append("firstentity.id as first_entity_id, firstentity.name as entity_name, "); + str.append("otherentity.id as second_entity_id, otherentity.name as second_entity_name, "); + str.append("eea.second_entity_type as second_entity_type "); + str.append("from m_entity_to_entity_access eea "); + str.append("left join m_code_value cv on (cv.code_value = "); + str.append("'"); + str.append(accessType.toStr()); + str.append("' "); + str.append("and eea.access_type_code_value_id = cv.id) "); + str.append("left join m_code c on (c.code_name = '"); + str.append(MifosEntityAccessConstants.ENTITY_ACCESS_CODENAME); + str.append("' and cv.code_id = c.id) "); + str.append("left join "); + str.append(firstEntityType.getTable()); + str.append(" firstentity on (eea.entity_type = "); + str.append("'"); + str.append(firstEntityType.getType()); + str.append("'"); + str.append(" and eea.entity_id = firstentity.id) left join "); + str.append(secondEntityType.getTable()); + str.append(" otherentity on (eea.second_entity_type = "); + str.append("'"); + str.append(secondEntityType.getType()); + str.append("' "); + str.append("and eea.second_entity_id = otherentity.id) "); + str.append("where eea.access_type_code_value_id = cv.id "); + str.append("and eea.entity_id = ? "); + logger.debug(str.toString()); + return str.toString(); + } + + private static final class MifosEntityAccessDataMapper implements RowMapper { + @Override + public MifosEntityAccessData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + final String entityType = rs.getString("entity_type"); + final Long entityId = rs.getLong("entity_id"); + final String entityName = rs.getString("entity_name"); + final Long accessId = rs.getLong("access_id"); + final String accessTypeDesc = rs.getString("access_type_desc"); + final String code = rs.getString("code"); + final Long secondEntityId = rs.getLong("second_entity_id"); + final String secondEntityName = rs.getString("second_entity_name"); + final String secondEntityType = rs.getString("second_entity_type"); + + MifosEntity firstEntity = null; + MifosEntityType etype = MifosEntityType.get(entityType); + if (entityId != null && etype != null) { + firstEntity = new MifosEntity(entityId, etype); + } + + MifosEntity secondEntity = null; + MifosEntityType secondetype = MifosEntityType.get(secondEntityType); + if (entityId != null && etype != null) { + secondEntity = new MifosEntity(secondEntityId, secondetype); + } + + MifosEntityAccessType accessType = null; + if (accessTypeDesc != null) { + accessType = MifosEntityAccessType.get(accessTypeDesc); + } + + MifosEntityAccessData returnMifosEntityAccessData = null; + if (firstEntity != null && secondEntity != null && accessType != null) { + returnMifosEntityAccessData = new MifosEntityAccessData(firstEntity, accessType, secondEntity); + } + return returnMifosEntityAccessData; + } + } + + @Override + public String getSQLQueryInClauseIDList_ForLoanProductsForOffice( + Long officeId, boolean includeAllOffices) { + + MifosEntityType firstEntityType = MifosEntityType.OFFICE; + MifosEntityAccessType accessType = MifosEntityAccessType.OFFICE_ACCESS_TO_LOAN_PRODUCTS; + MifosEntityType secondEntityType = MifosEntityType.LOAN_PRODUCT; + + return getSQLQueryInClause_WithListOfIDsForEntityAccess ( + officeId, firstEntityType, accessType, + secondEntityType, includeAllOffices); + } + + @Override + public String getSQLQueryInClauseIDList_ForSavingsProductsForOffice( + Long officeId, boolean includeAllOffices) { + + MifosEntityType firstEntityType = MifosEntityType.OFFICE; + MifosEntityAccessType accessType = MifosEntityAccessType.OFFICE_ACCESS_TO_SAVINGS_PRODUCTS; + MifosEntityType secondEntityType = MifosEntityType.SAVINGS_PRODUCT; + + return getSQLQueryInClause_WithListOfIDsForEntityAccess ( + officeId, firstEntityType, accessType, + secondEntityType, includeAllOffices); + } + + @Override + public String getSQLQueryInClauseIDList_ForChargesForOffice( + Long officeId, boolean includeAllOffices) { + + MifosEntityType firstEntityType = MifosEntityType.OFFICE; + MifosEntityAccessType accessType = MifosEntityAccessType.OFFICE_ACCESS_TO_CHARGES; + MifosEntityType secondEntityType = MifosEntityType.CHARGE; + + return getSQLQueryInClause_WithListOfIDsForEntityAccess ( + officeId, firstEntityType, accessType, + secondEntityType, includeAllOffices); + } + + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessUtil.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessUtil.java new file mode 100644 index 000000000..d0e5d5f93 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessUtil.java @@ -0,0 +1,130 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.infrastructure.entityaccess.service; + +import java.util.Collection; +import java.util.Iterator; + +import org.mifosplatform.infrastructure.configuration.domain.GlobalConfigurationProperty; +import org.mifosplatform.infrastructure.configuration.domain.GlobalConfigurationRepositoryWrapper; + + +import org.mifosplatform.infrastructure.codes.data.CodeValueData; +import org.mifosplatform.infrastructure.codes.domain.CodeValue; +import org.mifosplatform.infrastructure.codes.domain.CodeValueRepositoryWrapper; +import org.mifosplatform.infrastructure.codes.service.CodeValueReadPlatformService; +import org.mifosplatform.infrastructure.entityaccess.MifosEntityAccessConstants; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityAccessType; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityType; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; +import org.mifosplatform.useradministration.domain.AppUser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class MifosEntityAccessUtil { + + private final PlatformSecurityContext context; + private final GlobalConfigurationRepositoryWrapper globalConfigurationRepository; + private final CodeValueReadPlatformService codeValueReadPlatformService; + private final CodeValueRepositoryWrapper codeValueRepository; + private final MifosEntityAccessWriteService mifosEntityAccessWriteService; + private final MifosEntityAccessReadService mifosEntityAccessReadService; + + @Autowired + public MifosEntityAccessUtil ( + final PlatformSecurityContext context, + final GlobalConfigurationRepositoryWrapper globalConfigurationRepository, + final MifosEntityAccessWriteService mifosEntityAccessWriteService, + final CodeValueReadPlatformService codeValueReadPlatformService, + final CodeValueRepositoryWrapper codeValueRepository, + final MifosEntityAccessReadService mifosEntityAccessReadService) { + this.context = context; + this.globalConfigurationRepository = globalConfigurationRepository; + this.mifosEntityAccessWriteService = mifosEntityAccessWriteService; + this.codeValueReadPlatformService = codeValueReadPlatformService; + this.codeValueRepository = codeValueRepository; + this.mifosEntityAccessReadService = mifosEntityAccessReadService; + } + + + @Transactional + public void checkConfigurationAndAddProductResrictionsForUserOffice ( + final MifosEntityAccessType mifosEntityAccessType, + final MifosEntityType mifosEntityType, + final Long productOrChargeId) { + + AppUser thisUser = this.context.authenticatedUser(); + + // check if the office specific products are enabled. If yes, then save this product or charge against a specific office + // i.e. this product or charge is specific for this office. + + final GlobalConfigurationProperty property = this.globalConfigurationRepository + .findOneByNameWithNotFoundDetection( + MifosEntityAccessConstants.GLOBAL_CONFIG_FOR_OFFICE_SPECIFIC_PRODUCTS); + if (property.isEnabled() ) { + // If this property is enabled, then Mifos need to restrict access to this loan product to only the office of the current user + final GlobalConfigurationProperty restrictToUserOfficeProperty = this.globalConfigurationRepository + .findOneByNameWithNotFoundDetection( + MifosEntityAccessConstants.GLOBAL_CONFIG_FOR_RESTRICT_PRODUCTS_TO_USER_OFFICE); + + if (restrictToUserOfficeProperty.isEnabled() ) { + final Long officeId = thisUser.getOffice().getId(); + Collection codevalues = codeValueReadPlatformService.retrieveCodeValuesByCode( + MifosEntityAccessConstants.ENTITY_ACCESS_CODENAME); + if (codevalues != null) { + Iterator iterator = codevalues.iterator(); + while(iterator.hasNext()) { + CodeValueData oneCodeValue = iterator.next(); + if ( (oneCodeValue != null) && + (oneCodeValue.getName().equals(mifosEntityAccessType.toStr())) ) { + CodeValue cv = codeValueRepository.findOneByCodeNameAndLabelWithNotFoundDetection( + MifosEntityAccessConstants.ENTITY_ACCESS_CODENAME, + mifosEntityAccessType.toStr() + ); + if (cv != null) { + mifosEntityAccessWriteService.addNewEntityAccess( + MifosEntityType.OFFICE.getType(), officeId, + cv, + mifosEntityType.getType(), productOrChargeId); + } + } + } + } + } + } + + } + + public String getSQLWhereClauseForProductIDsForUserOffice_ifGlobalConfigEnabled ( + MifosEntityType mifosEntityType) { + String inClause = ""; + + final GlobalConfigurationProperty property = this.globalConfigurationRepository + .findOneByNameWithNotFoundDetection( + MifosEntityAccessConstants.GLOBAL_CONFIG_FOR_OFFICE_SPECIFIC_PRODUCTS); + + if (property.isEnabled() ) { + // Get 'SQL In Clause' for fetching only products/charges that are relevant for current user's office + if (mifosEntityType.equals(MifosEntityType.SAVINGS_PRODUCT)) { + inClause = mifosEntityAccessReadService. + getSQLQueryInClauseIDList_ForSavingsProductsForOffice ( + this.context.authenticatedUser().getOffice().getId(), false); + } else if (mifosEntityType.equals(MifosEntityType.LOAN_PRODUCT)) { + inClause = mifosEntityAccessReadService. + getSQLQueryInClauseIDList_ForLoanProductsForOffice ( + this.context.authenticatedUser().getOffice().getId(), false); + } else if (mifosEntityType.equals(MifosEntityType.CHARGE)) { + inClause = mifosEntityAccessReadService. + getSQLQueryInClauseIDList_ForChargesForOffice( + this.context.authenticatedUser().getOffice().getId(), false); + } + } + return inClause; + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessWriteService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessWriteService.java new file mode 100644 index 000000000..0ae7123cd --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessWriteService.java @@ -0,0 +1,30 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.infrastructure.entityaccess.service; + +import org.mifosplatform.infrastructure.codes.domain.CodeValue; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; + +public interface MifosEntityAccessWriteService { + + CommandProcessingResult createEntityAccess ( + final JsonCommand command); + + void addNewEntityAccess (final String entityType, final Long entityId, + final CodeValue accessType, + final String secondEntityType, final Long secondEntityId); + + /* + CommandProcessingResult updateEntityAccess ( + final Long entityAccessId, final JsonCommand command); + + CommandProcessingResult removeEntityAccess ( + final String entityType, final Long entityId, + final Long accessType, + final String secondEntityType, final Long secondEntityId); + */ +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessWriteServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessWriteServiceImpl.java new file mode 100644 index 000000000..f4bd40626 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/entityaccess/service/MifosEntityAccessWriteServiceImpl.java @@ -0,0 +1,72 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.infrastructure.entityaccess.service; + +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; + + +import org.mifosplatform.infrastructure.codes.domain.CodeValue; +import org.mifosplatform.infrastructure.codes.domain.CodeValueRepositoryWrapper; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityAccess; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityAccessRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class MifosEntityAccessWriteServiceImpl implements + MifosEntityAccessWriteService { + + private final static Logger logger = LoggerFactory.getLogger(MifosEntityAccessWriteServiceImpl.class); + private final CodeValueRepositoryWrapper codeValueRepositoryWrapper; + private final MifosEntityAccessRepository entityAccessRepository; + + @Autowired + public MifosEntityAccessWriteServiceImpl( + final MifosEntityAccessRepository entityAccessRepository, + final CodeValueRepositoryWrapper codeValueRepositoryWrapper) { + this.entityAccessRepository = entityAccessRepository; + this.codeValueRepositoryWrapper = codeValueRepositoryWrapper; + } + + @Override + public CommandProcessingResult createEntityAccess(JsonCommand command) { + // TODO Auto-generated method stub + return null; + } + + @Override + @Transactional + public void addNewEntityAccess (final String entityType, final Long entityId, + final CodeValue accessType, + final String secondEntityType, final Long secondEntityId) { + MifosEntityAccess entityAccess = MifosEntityAccess.createNew(entityType, entityId, + accessType, secondEntityType, secondEntityId); + entityAccessRepository.save(entityAccess); + } + + /* + @Override + public CommandProcessingResult updateEntityAccess(Long entityAccessId, + JsonCommand command) { + // TODO Auto-generated method stub + return null; + } + + @Override + public CommandProcessingResult removeEntityAccess(String entityType, + Long entityId, Long accessType, String secondEntityType, + Long secondEntityId) { + // TODO Auto-generated method stub + return null; + } + */ + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeReadPlatformServiceImpl.java index 1bca0f260..4149a1510 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeReadPlatformServiceImpl.java @@ -16,6 +16,8 @@ import org.joda.time.MonthDay; import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.domain.JdbcSupport; import org.mifosplatform.infrastructure.core.service.RoutingDataSource; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityType; +import org.mifosplatform.infrastructure.entityaccess.service.MifosEntityAccessUtil; import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.organisation.monetary.service.CurrencyReadPlatformService; import org.mifosplatform.portfolio.charge.data.ChargeData; @@ -42,15 +44,18 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService private final CurrencyReadPlatformService currencyReadPlatformService; private final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService; private final DropdownReadPlatformService dropdownReadPlatformService; - + private final MifosEntityAccessUtil mifosEntityAccessUtil; + @Autowired public ChargeReadPlatformServiceImpl(final CurrencyReadPlatformService currencyReadPlatformService, final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService, final RoutingDataSource dataSource, - final DropdownReadPlatformService dropdownReadPlatformService) { + final DropdownReadPlatformService dropdownReadPlatformService, + final MifosEntityAccessUtil mifosEntityAccessUtil) { this.chargeDropdownReadPlatformService = chargeDropdownReadPlatformService; this.jdbcTemplate = new JdbcTemplate(dataSource); this.currencyReadPlatformService = currencyReadPlatformService; this.dropdownReadPlatformService = dropdownReadPlatformService; + this.mifosEntityAccessUtil = mifosEntityAccessUtil; } @Override @@ -58,7 +63,11 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService public Collection retrieveAllCharges() { final ChargeMapper rm = new ChargeMapper(); - final String sql = "select " + rm.chargeSchema() + " where c.is_deleted=0 order by c.name "; + String sql = "select " + rm.chargeSchema() + " where c.is_deleted=0 "; + + sql += addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled(); + + sql += " order by c.name "; return this.jdbcTemplate.query(sql, rm, new Object[] {}); } @@ -67,8 +76,12 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService public Collection retrieveAllChargesForCurrency(String currencyCode) { final ChargeMapper rm = new ChargeMapper(); - final String sql = "select " + rm.chargeSchema() + " where c.is_deleted=0 and c.currency_code='" + currencyCode - + "' order by c.name "; + String sql = "select " + rm.chargeSchema() + " where c.is_deleted=0 and c.currency_code='" + currencyCode + + "' "; + + sql += addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled(); + + sql += " order by c.name "; return this.jdbcTemplate.query(sql, rm, new Object[] {}); } @@ -78,8 +91,10 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService try { final ChargeMapper rm = new ChargeMapper(); - final String sql = "select " + rm.chargeSchema() + " where c.id = ? and c.is_deleted=0 "; - + String sql = "select " + rm.chargeSchema() + " where c.id = ? and c.is_deleted=0 "; + + sql += addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled(); + return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { chargeId }); } catch (final EmptyResultDataAccessException e) { throw new ChargeNotFoundException(chargeId); @@ -112,7 +127,9 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService public Collection retrieveLoanProductCharges(final Long loanProductId) { final ChargeMapper rm = new ChargeMapper(); - final String sql = "select " + rm.loanProductChargeSchema() + " where c.is_deleted=0 and c.is_active=1 and plc.product_loan_id=?"; + String sql = "select " + rm.loanProductChargeSchema() + " where c.is_deleted=0 and c.is_active=1 and plc.product_loan_id=? "; + + sql += addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled(); return this.jdbcTemplate.query(sql, rm, new Object[] { loanProductId }); } @@ -122,8 +139,9 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService final ChargeMapper rm = new ChargeMapper(); - final String sql = "select " + rm.loanProductChargeSchema() - + " where c.is_deleted=0 and c.is_active=1 and plc.product_loan_id=? and c.charge_time_enum=?"; + String sql = "select " + rm.loanProductChargeSchema() + + " where c.is_deleted=0 and c.is_active=1 and plc.product_loan_id=? and c.charge_time_enum=? "; + sql += addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled(); return this.jdbcTemplate.query(sql, rm, new Object[] { loanProductId, chargeTime.getValue() }); } @@ -133,7 +151,9 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService final ChargeMapper rm = new ChargeMapper(); Object[] params = new Object[] { ChargeAppliesTo.LOAN.getValue() }; String sql = "select " + rm.chargeSchema() - + " where c.is_deleted=0 and c.is_active=1 and c.is_penalty=0 and c.charge_applies_to_enum=? order by c.name "; + + " where c.is_deleted=0 and c.is_active=1 and c.is_penalty=0 and c.charge_applies_to_enum=? "; + sql += addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled(); + sql += " order by c.name "; return this.jdbcTemplate.query(sql, rm, params); } @@ -145,7 +165,10 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService Object[] params = new Object[] { loanId, ChargeAppliesTo.LOAN.getValue() }; params = processChargeExclusionsForLoans(excludeChargeTimes, excludeClause, params); String sql = "select " + rm.chargeSchema() + " join m_loan la on la.currency_code = c.currency_code" + " where la.id=?" - + " and c.is_deleted=0 and c.is_active=1 and c.charge_applies_to_enum=?" + excludeClause + " order by c.name "; + + " and c.is_deleted=0 and c.is_active=1 and c.charge_applies_to_enum=?" + excludeClause + " "; + sql += addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled(); + sql += " order by c.name "; + return this.jdbcTemplate.query(sql, rm, params); } @@ -179,7 +202,9 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService Object[] params = new Object[] { loanProductId, ChargeAppliesTo.LOAN.getValue() }; params = processChargeExclusionsForLoans(excludeChargeTimes, excludeClause, params); String sql = "select " + rm.chargeSchema() + " join m_product_loan lp on lp.currency_code = c.currency_code" + " where lp.id=?" - + " and c.is_deleted=0 and c.is_active=1 and c.charge_applies_to_enum=?" + excludeClause + " order by c.name "; + + " and c.is_deleted=0 and c.is_active=1 and c.charge_applies_to_enum=?" + excludeClause + " "; + sql += addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled(); + sql += " order by c.name "; return this.jdbcTemplate.query(sql, rm, params); } @@ -188,10 +213,27 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService public Collection retrieveLoanApplicablePenalties() { final ChargeMapper rm = new ChargeMapper(); - final String sql = "select " + rm.chargeSchema() - + " where c.is_deleted=0 and c.is_active=1 and c.is_penalty=1 and c.charge_applies_to_enum=? order by c.name "; + String sql = "select " + rm.chargeSchema() + + " where c.is_deleted=0 and c.is_active=1 and c.is_penalty=1 and c.charge_applies_to_enum=? "; + sql += addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled(); + sql += " order by c.name "; return this.jdbcTemplate.query(sql, rm, new Object[] { ChargeAppliesTo.LOAN.getValue() }); } + + private String addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled () { + + String sql = ""; + + // Check if branch specific products are enabled. If yes, fetch only charges mapped to current user's office + String inClause = mifosEntityAccessUtil. + getSQLWhereClauseForProductIDsForUserOffice_ifGlobalConfigEnabled( + MifosEntityType.CHARGE); + if ( (inClause != null) && (!(inClause.trim().isEmpty())) ) { + sql += " and c.id in ( " + inClause + " ) "; + } + + return sql; + } private static final class ChargeMapper implements RowMapper { @@ -271,11 +313,13 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService final ChargeMapper rm = new ChargeMapper(); String sql = "select " + rm.chargeSchema() - + " where c.is_deleted=0 and c.is_active=1 and c.charge_applies_to_enum=? order by c.name "; + + " where c.is_deleted=0 and c.is_active=1 and c.charge_applies_to_enum=? "; if (feeChargesOnly) { sql = "select " + rm.chargeSchema() - + " where c.is_deleted=0 and c.is_active=1 and c.is_penalty=0 and c.charge_applies_to_enum=? order by c.name "; + + " where c.is_deleted=0 and c.is_active=1 and c.is_penalty=0 and c.charge_applies_to_enum=? "; } + sql += addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled(); + sql += " order by c.name "; return this.jdbcTemplate.query(sql, rm, new Object[] { ChargeAppliesTo.SAVINGS.getValue() }); } @@ -284,8 +328,10 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService public Collection retrieveSavingsApplicablePenalties() { final ChargeMapper rm = new ChargeMapper(); - final String sql = "select " + rm.chargeSchema() - + " where c.is_deleted=0 and c.is_active=1 and c.is_penalty=1 and c.charge_applies_to_enum=? order by c.name "; + String sql = "select " + rm.chargeSchema() + + " where c.is_deleted=0 and c.is_active=1 and c.is_penalty=1 and c.charge_applies_to_enum=? "; + sql += addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled(); + sql += " order by c.name "; return this.jdbcTemplate.query(sql, rm, new Object[] { ChargeAppliesTo.SAVINGS.getValue() }); } @@ -293,8 +339,9 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService public Collection retrieveSavingsProductCharges(final Long savingsProductId) { final ChargeMapper rm = new ChargeMapper(); - final String sql = "select " + rm.savingsProductChargeSchema() - + " where c.is_deleted=0 and c.is_active=1 and spc.savings_product_id=?"; + String sql = "select " + rm.savingsProductChargeSchema() + + " where c.is_deleted=0 and c.is_active=1 and spc.savings_product_id=? "; + sql += addInClauseToSQL_toLimitChargesMappedToOffice_ifOfficeSpecificProductsEnabled(); return this.jdbcTemplate.query(sql, rm, new Object[] { savingsProductId }); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java index 8c8b726b6..d65b0275d 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java @@ -15,6 +15,10 @@ import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; import org.mifosplatform.infrastructure.core.service.RoutingDataSource; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityAccessType; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityType; +import org.mifosplatform.infrastructure.entityaccess.service.MifosEntityAccessUtil; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.portfolio.charge.domain.Charge; import org.mifosplatform.portfolio.charge.domain.ChargeRepository; import org.mifosplatform.portfolio.charge.exception.ChargeCannotBeDeletedException; @@ -36,21 +40,27 @@ import org.springframework.transaction.annotation.Transactional; public class ChargeWritePlatformServiceJpaRepositoryImpl implements ChargeWritePlatformService { private final static Logger logger = LoggerFactory.getLogger(ChargeWritePlatformServiceJpaRepositoryImpl.class); - + private final PlatformSecurityContext context; private final ChargeDefinitionCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final JdbcTemplate jdbcTemplate; private final DataSource dataSource; private final ChargeRepository chargeRepository; private final LoanProductRepository loanProductRepository; + private final MifosEntityAccessUtil mifosEntityAccessUtil; @Autowired - public ChargeWritePlatformServiceJpaRepositoryImpl(final ChargeDefinitionCommandFromApiJsonDeserializer fromApiJsonDeserializer, - final ChargeRepository chargeRepository, final LoanProductRepository loanProductRepository, final RoutingDataSource dataSource) { + public ChargeWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, + final ChargeDefinitionCommandFromApiJsonDeserializer fromApiJsonDeserializer, + final ChargeRepository chargeRepository, final LoanProductRepository loanProductRepository, final RoutingDataSource dataSource, + final MifosEntityAccessUtil mifosEntityAccessUtil + ) { + this.context = context; this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.dataSource = dataSource; this.jdbcTemplate = new JdbcTemplate(this.dataSource); this.chargeRepository = chargeRepository; this.loanProductRepository = loanProductRepository; + this.mifosEntityAccessUtil = mifosEntityAccessUtil; } @Transactional @@ -58,11 +68,19 @@ public class ChargeWritePlatformServiceJpaRepositoryImpl implements ChargeWriteP @CacheEvict(value = "charges", key = "T(org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat('ch')") public CommandProcessingResult createCharge(final JsonCommand command) { try { + this.context.authenticatedUser(); this.fromApiJsonDeserializer.validateForCreate(command.json()); final Charge charge = Charge.fromJson(command); this.chargeRepository.save(charge); + // check if the office specific products are enabled. If yes, then save this savings product against a specific office + // i.e. this savings product is specific for this office. + mifosEntityAccessUtil.checkConfigurationAndAddProductResrictionsForUserOffice( + MifosEntityAccessType.OFFICE_ACCESS_TO_CHARGES, + MifosEntityType.CHARGE, + charge.getId()); + return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(charge.getId()).build(); } catch (final DataIntegrityViolationException dve) { handleDataIntegrityIssues(command, dve); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java index f6d36339c..3f0a96398 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java @@ -17,6 +17,8 @@ import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.domain.JdbcSupport; import org.mifosplatform.infrastructure.core.service.DateUtils; import org.mifosplatform.infrastructure.core.service.RoutingDataSource; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityType; +import org.mifosplatform.infrastructure.entityaccess.service.MifosEntityAccessUtil; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.portfolio.charge.data.ChargeData; @@ -40,13 +42,16 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo private final PlatformSecurityContext context; private final JdbcTemplate jdbcTemplate; private final ChargeReadPlatformService chargeReadPlatformService; + private final MifosEntityAccessUtil mifosEntityAccessUtil; @Autowired public LoanProductReadPlatformServiceImpl(final PlatformSecurityContext context, - final ChargeReadPlatformService chargeReadPlatformService, final RoutingDataSource dataSource) { + final ChargeReadPlatformService chargeReadPlatformService, final RoutingDataSource dataSource, + final MifosEntityAccessUtil mifosEntityAccessUtil) { this.context = context; this.chargeReadPlatformService = chargeReadPlatformService; this.jdbcTemplate = new JdbcTemplate(dataSource); + this.mifosEntityAccessUtil = mifosEntityAccessUtil; } @Override @@ -79,7 +84,15 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo final LoanProductMapper rm = new LoanProductMapper(null, null); - final String sql = "select " + rm.loanProductSchema(); + String sql = "select " + rm.loanProductSchema(); + + // Check if branch specific products are enabled. If yes, fetch only products mapped to current user's office + String inClause = mifosEntityAccessUtil. + getSQLWhereClauseForProductIDsForUserOffice_ifGlobalConfigEnabled( + MifosEntityType.LOAN_PRODUCT); + if ( (inClause != null) && (!(inClause.trim().isEmpty())) ) { + sql += " where lp.id in ( " + inClause + " ) "; + } return this.jdbcTemplate.query(sql, rm, new Object[] {}); } @@ -91,7 +104,15 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo final LoanProductLookupMapper rm = new LoanProductLookupMapper(); - final String sql = "select " + rm.schema(); + String sql = "select " + rm.schema(); + + // Check if branch specific products are enabled. If yes, fetch only products mapped to current user's office + String inClause = mifosEntityAccessUtil. + getSQLWhereClauseForProductIDsForUserOffice_ifGlobalConfigEnabled( + MifosEntityType.LOAN_PRODUCT); + if ( (inClause != null) && (!(inClause.trim().isEmpty())) ) { + sql += " where id in ( " + inClause + " ) "; + } return this.jdbcTemplate.query(sql, rm, new Object[] {}); } @@ -350,7 +371,15 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo final LoanProductMapper rm = new LoanProductMapper(null, null); - final String sql = "select " + rm.loanProductSchema() + " where lp.currency_code='" + currencyCode + "'"; + String sql = "select " + rm.loanProductSchema() + " where lp.currency_code='" + currencyCode + "'"; + + // Check if branch specific products are enabled. If yes, fetch only products mapped to current user's office + String inClause = mifosEntityAccessUtil. + getSQLWhereClauseForProductIDsForUserOffice_ifGlobalConfigEnabled( + MifosEntityType.LOAN_PRODUCT); + if ( (inClause != null) && (!(inClause.trim().isEmpty())) ) { + sql += " and id in ( " + inClause + " ) "; + } return this.jdbcTemplate.query(sql, rm, new Object[] {}); } @@ -362,7 +391,15 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo final LoanProductLookupMapper rm = new LoanProductLookupMapper(); - final String sql = "Select " + rm.productMixSchema(); + String sql = "Select " + rm.productMixSchema(); + + // Check if branch specific products are enabled. If yes, fetch only products mapped to current user's office + String inClause = mifosEntityAccessUtil. + getSQLWhereClauseForProductIDsForUserOffice_ifGlobalConfigEnabled( + MifosEntityType.LOAN_PRODUCT); + if ( (inClause != null) && (!(inClause.trim().isEmpty())) ) { + sql += " and lp.id in ( " + inClause + " ) "; + } return this.jdbcTemplate.query(sql, rm, new Object[] {}); } @@ -374,8 +411,25 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo final LoanProductLookupMapper rm = new LoanProductLookupMapper(); - final String sql = "Select " + rm.restrictedProductsSchema() + " where pm.product_id=? UNION Select " + String sql = "Select " + rm.restrictedProductsSchema() + " where pm.product_id=? "; + // Check if branch specific products are enabled. If yes, fetch only products mapped to current user's office + String inClause1 = mifosEntityAccessUtil. + getSQLWhereClauseForProductIDsForUserOffice_ifGlobalConfigEnabled( + MifosEntityType.LOAN_PRODUCT); + if ( (inClause1 != null) && (!(inClause1.trim().isEmpty())) ) { + sql += " and rp.id in ( " + inClause1 + " ) "; + } + + sql += " UNION Select " + rm.derivedRestrictedProductsSchema() + " where pm.restricted_product_id=?"; + + // Check if branch specific products are enabled. If yes, fetch only products mapped to current user's office + String inClause2 = mifosEntityAccessUtil. + getSQLWhereClauseForProductIDsForUserOffice_ifGlobalConfigEnabled( + MifosEntityType.LOAN_PRODUCT); + if ( (inClause2 != null) && (!(inClause2.trim().isEmpty())) ) { + sql += " and lp.id in ( " + inClause2 + " ) "; + } return this.jdbcTemplate.query(sql, rm, new Object[] { productId, productId }); } @@ -387,7 +441,17 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo final LoanProductLookupMapper rm = new LoanProductLookupMapper(); - final String sql = "Select " + rm.schema() + " where lp.id not in (" + String sql = "Select " + rm.schema() + " where "; + + // Check if branch specific products are enabled. If yes, fetch only products mapped to current user's office + String inClause = mifosEntityAccessUtil. + getSQLWhereClauseForProductIDsForUserOffice_ifGlobalConfigEnabled( + MifosEntityType.LOAN_PRODUCT); + if ( (inClause != null) && (!(inClause.trim().isEmpty())) ) { + sql += " lp.id in ( " + inClause + " ) and "; + } + + sql += "lp.id not in (" + "Select pm.restricted_product_id from m_product_mix pm where pm.product_id=? " + "UNION " + "Select pm.product_id from m_product_mix pm where pm.restricted_product_id=?)"; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java index e8ee2d9da..17c099ea4 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java @@ -15,6 +15,9 @@ import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityAccessType; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityType; +import org.mifosplatform.infrastructure.entityaccess.service.MifosEntityAccessUtil; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.portfolio.charge.domain.Charge; import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper; @@ -53,6 +56,7 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro private final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository; private final ChargeRepositoryWrapper chargeRepository; private final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService; + private final MifosEntityAccessUtil mifosEntityAccessUtil; @Autowired public LoanProductWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, @@ -60,7 +64,8 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro final AprCalculator aprCalculator, final FundRepository fundRepository, final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository, final ChargeRepositoryWrapper chargeRepository, - final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService) { + final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService, + final MifosEntityAccessUtil mifosEntityAccessUtil) { this.context = context; this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.loanProductRepository = loanProductRepository; @@ -69,6 +74,7 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro this.loanTransactionProcessingStrategyRepository = loanTransactionProcessingStrategyRepository; this.chargeRepository = chargeRepository; this.accountMappingWritePlatformService = accountMappingWritePlatformService; + this.mifosEntityAccessUtil = mifosEntityAccessUtil; } @Transactional @@ -98,6 +104,12 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro // save accounting mappings this.accountMappingWritePlatformService.createLoanProductToGLAccountMapping(loanproduct.getId(), command); + // check if the office specific products are enabled. If yes, then save this savings product against a specific office + // i.e. this savings product is specific for this office. + mifosEntityAccessUtil.checkConfigurationAndAddProductResrictionsForUserOffice( + MifosEntityAccessType.OFFICE_ACCESS_TO_LOAN_PRODUCTS, + MifosEntityType.LOAN_PRODUCT, + loanproduct.getId()); return new CommandProcessingResultBuilder() // .withCommandId(command.commandId()) // diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductReadPlatformServiceImpl.java index 06d7249f5..cbcdb9a32 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductReadPlatformServiceImpl.java @@ -14,6 +14,8 @@ import org.mifosplatform.accounting.common.AccountingEnumerations; import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.domain.JdbcSupport; import org.mifosplatform.infrastructure.core.service.RoutingDataSource; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityType; +import org.mifosplatform.infrastructure.entityaccess.service.MifosEntityAccessUtil; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.portfolio.savings.DepositAccountType; @@ -32,11 +34,14 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead private final JdbcTemplate jdbcTemplate; private final SavingProductMapper savingsProductRowMapper = new SavingProductMapper(); private final SavingProductLookupMapper savingsProductLookupsRowMapper = new SavingProductLookupMapper(); + private final MifosEntityAccessUtil mifosEntityAccessUtil; @Autowired - public SavingsProductReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource) { + public SavingsProductReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource, + final MifosEntityAccessUtil mifosEntityAccessUtil) { this.context = context; this.jdbcTemplate = new JdbcTemplate(dataSource); + this.mifosEntityAccessUtil = mifosEntityAccessUtil; } @Override @@ -44,7 +49,15 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead this.context.authenticatedUser(); - final String sql = "select " + this.savingsProductRowMapper.schema() + "where sp.deposit_type_enum = ?"; + String sql = "select " + this.savingsProductRowMapper.schema() + "where sp.deposit_type_enum = ?"; + + // Check if branch specific products are enabled. If yes, fetch only products mapped to current user's office + String inClause = mifosEntityAccessUtil. + getSQLWhereClauseForProductIDsForUserOffice_ifGlobalConfigEnabled( + MifosEntityType.SAVINGS_PRODUCT); + if ( (inClause != null) && (!(inClause.trim().isEmpty())) ) { + sql += " and sp.id in ( " + inClause + " ) "; + } return this.jdbcTemplate.query(sql, this.savingsProductRowMapper, new Object[] { DepositAccountType.SAVINGS_DEPOSIT.getValue() }); } @@ -52,7 +65,16 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead @Override public Collection retrieveAllForLookup() { - final String sql = "select " + this.savingsProductLookupsRowMapper.schema() + " where sp.deposit_type_enum = ?"; + String sql = "select " + this.savingsProductLookupsRowMapper.schema() + " where sp.deposit_type_enum = ? "; + + // Check if branch specific products are enabled. If yes, fetch only products mapped to current user's office + String inClause = mifosEntityAccessUtil. + getSQLWhereClauseForProductIDsForUserOffice_ifGlobalConfigEnabled( + MifosEntityType.SAVINGS_PRODUCT); + if ( (inClause != null) && (!(inClause.trim().isEmpty())) ) { + sql += " and id in ( " + inClause + " ) "; + } + return this.jdbcTemplate.query(sql, this.savingsProductLookupsRowMapper, new Object[] { DepositAccountType.SAVINGS_DEPOSIT.getValue() }); @@ -188,8 +210,24 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead @Override public Collection retrieveAllForLookupByType(Boolean isOverdraftType) { String sql = "select " + this.savingsProductLookupsRowMapper.schema(); + + boolean inClauseAdded = false; + + // Check if branch specific products are enabled. If yes, fetch only products mapped to current user's office + String inClause = mifosEntityAccessUtil. + getSQLWhereClauseForProductIDsForUserOffice_ifGlobalConfigEnabled( + MifosEntityType.SAVINGS_PRODUCT); + if ( (inClause != null) && (!(inClause.trim().isEmpty())) ) { + sql += " where id in ( " + inClause + " ) "; + inClauseAdded = true; + } + if (isOverdraftType != null) { - sql += " where sp.allow_overdraft=?"; + if (inClauseAdded) { + sql += " and sp.allow_overdraft=?"; + } else { + sql += " where sp.allow_overdraft=?"; + } return this.jdbcTemplate.query(sql, this.savingsProductLookupsRowMapper, isOverdraftType); } @@ -202,7 +240,15 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead this.context.authenticatedUser(); - final String sql = "select " + this.savingsProductRowMapper.schema() + " where sp.currency_code='" + currencyCode + "'"; + String sql = "select " + this.savingsProductRowMapper.schema() + " where sp.currency_code='" + currencyCode + "'"; + + // Check if branch specific products are enabled. If yes, fetch only products mapped to current user's office + String inClause = mifosEntityAccessUtil. + getSQLWhereClauseForProductIDsForUserOffice_ifGlobalConfigEnabled( + MifosEntityType.SAVINGS_PRODUCT); + if ( (inClause != null) && (!(inClause.trim().isEmpty())) ) { + sql += " and id in ( " + inClause + " ) "; + } return this.jdbcTemplate.query(sql, this.savingsProductRowMapper); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductWritePlatformServiceJpaRepositoryImpl.java index 8bb6b7228..d4a62f17f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductWritePlatformServiceJpaRepositoryImpl.java @@ -16,6 +16,9 @@ import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityAccessType; +import org.mifosplatform.infrastructure.entityaccess.domain.MifosEntityType; +import org.mifosplatform.infrastructure.entityaccess.service.MifosEntityAccessUtil; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.portfolio.charge.domain.Charge; import org.mifosplatform.portfolio.savings.DepositAccountType; @@ -40,18 +43,22 @@ public class SavingsProductWritePlatformServiceJpaRepositoryImpl implements Savi private final SavingsProductDataValidator fromApiJsonDataValidator; private final SavingsProductAssembler savingsProductAssembler; private final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService; + private final MifosEntityAccessUtil mifosEntityAccessUtil; @Autowired public SavingsProductWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final SavingsProductRepository savingProductRepository, final SavingsProductDataValidator fromApiJsonDataValidator, final SavingsProductAssembler savingsProductAssembler, - final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService) { + final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService, + final MifosEntityAccessUtil mifosEntityAccessUtil + ) { this.context = context; this.savingProductRepository = savingProductRepository; this.fromApiJsonDataValidator = fromApiJsonDataValidator; this.savingsProductAssembler = savingsProductAssembler; this.logger = LoggerFactory.getLogger(SavingsProductWritePlatformServiceJpaRepositoryImpl.class); this.accountMappingWritePlatformService = accountMappingWritePlatformService; + this.mifosEntityAccessUtil = mifosEntityAccessUtil; } /* @@ -96,6 +103,13 @@ public class SavingsProductWritePlatformServiceJpaRepositoryImpl implements Savi // save accounting mappings this.accountMappingWritePlatformService.createSavingProductToGLAccountMapping(product.getId(), command, DepositAccountType.SAVINGS_DEPOSIT); + + // check if the office specific products are enabled. If yes, then save this savings product against a specific office + // i.e. this savings product is specific for this office. + mifosEntityAccessUtil.checkConfigurationAndAddProductResrictionsForUserOffice( + MifosEntityAccessType.OFFICE_ACCESS_TO_SAVINGS_PRODUCTS, + MifosEntityType.SAVINGS_PRODUCT, + product.getId()); return new CommandProcessingResultBuilder() // .withEntityId(product.getId()) // diff --git a/mifosng-provider/src/main/resources/sql/migrations/core_db/V225__entity_to_entity_access.sql b/mifosng-provider/src/main/resources/sql/migrations/core_db/V225__entity_to_entity_access.sql new file mode 100644 index 000000000..b1b3cdf46 --- /dev/null +++ b/mifosng-provider/src/main/resources/sql/migrations/core_db/V225__entity_to_entity_access.sql @@ -0,0 +1,45 @@ +-- Code required to store various types of Entity to Entity Access types that Mifos Supports +insert into m_code (code_name, is_system_defined) +values ('Entity to Entity Access Types', 1); + +-- Three Code Values required to support: +-- a) Loan Products restricted to specific Offices +-- b) Savings Products restricted to specific Offices +-- c) Fees/Charges restricted to specific Offices +insert into m_code_value (code_id, code_value, order_position) +values ( + (select id from m_code where code_name = 'Entity to Entity Access Types'), + 'Office Access to Loan Products', 0); + +insert into m_code_value (code_id, code_value, order_position) +values ( + (select id from m_code where code_name = 'Entity to Entity Access Types'), + 'Office Access to Savings Products', 0); + +insert into m_code_value (code_id, code_value, order_position) +values ( + (select id from m_code where code_name = 'Entity to Entity Access Types'), + 'Office Access to Fees/Charges', 0); + +-- Table where the actual restrictions will be stored +CREATE TABLE `m_entity_to_entity_access` ( + `id` BIGINT(20) NOT NULL AUTO_INCREMENT, + `entity_type` VARCHAR(50) NOT NULL, + `entity_id` BIGINT(20) NOT NULL, + `access_type_code_value_id` INT(11) NOT NULL, + `second_entity_type` VARCHAR(50) NOT NULL, + `second_entity_id` BIGINT(20) NOT NULL, + PRIMARY KEY (`id`), + INDEX `IDX_OFFICE` (`entity_type`,`entity_id`), + UNIQUE KEY `id_uniq_m_entity_to_entity_access` (`entity_type`,`entity_id`,`access_type_code_value_id`,`second_entity_type`,`second_entity_id`), + CONSTRAINT `FK_access_type_code_m_code_value` FOREIGN KEY (`access_type_code_value_id`) REFERENCES `m_code_value` (`id`) +); + +-- Global Configurations for Entity access restrictions +insert into c_configuration (name, value, enabled, description) + values ('office-specific-products-enabled', 0, 0, + 'Whether products and fees should be office specific or not? This property should NOT be changed once Mifos is Live.'); + +insert into c_configuration (name, value, enabled, description) + values ('restrict-products-to-user-office', 0, 0, + 'This should be enabled only if, products & fees are office specific (i.e. office-specific-products-enabled is enabled). This property specifies if the products should be auto-restricted to office of the user who created the proudct? Note: This property should NOT be changed once Mifos is Live.');