Branch Specific Products and Charges - initial commit

This commit is contained in:
Binny G Sreevas
2014-12-06 14:16:28 +05:30
parent c7f3f416ad
commit 9d11434ee7
26 changed files with 1230 additions and 38 deletions
@@ -53,4 +53,8 @@ public class CodeValueData implements Serializable {
public Long getId() {
return this.id;
}
public String getName() {
return this.name;
}
}
@@ -11,4 +11,6 @@ import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface CodeValueRepository extends JpaRepository<CodeValue, Long>, JpaSpecificationExecutor<CodeValue> {
CodeValue findByCodeNameAndId(String codeName, Long id);
CodeValue findByCodeNameAndLabel (String codeName, String label);
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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;
}
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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<Long> {
@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<String, Object> update(final JsonCommand command) {
final Map<String, Object> 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;
}
}
@@ -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<MifosEntityAccess, Long>, JpaSpecificationExecutor<MifosEntityAccess> {
// no added behaviour
}
@@ -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;
/**
* <p>
* Wrapper for {@link MifosEntityAccessRepository} that adds NULL checking and Error
* handling capabilities
* </p>
*/
@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);
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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());
}
}
@@ -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);
}
}
@@ -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<MifosEntityAccessData> 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);
}
@@ -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<MifosEntityAccessData> 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<MifosEntityAccessData> 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<MifosEntityAccessData> 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<MifosEntityAccessData> {
@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);
}
}
@@ -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<CodeValueData> codevalues = codeValueReadPlatformService.retrieveCodeValuesByCode(
MifosEntityAccessConstants.ENTITY_ACCESS_CODENAME);
if (codevalues != null) {
Iterator<CodeValueData> 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;
}
}
@@ -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);
*/
}
@@ -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;
}
*/
}
@@ -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<ChargeData> 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<ChargeData> 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<ChargeData> 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<ChargeData> 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<ChargeData> {
@@ -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<ChargeData> 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<ChargeData> 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 });
}
@@ -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);
@@ -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=?)";
@@ -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()) //
@@ -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<SavingsProductData> 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<SavingsProductData> 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);
}
@@ -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()) //
@@ -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.');