diff --git a/mifosng-db/patches/11-ddl_group_level_col_name_changed.sql b/mifosng-db/patches/11-ddl_group_level_col_name_changed.sql new file mode 100644 index 000000000..56a9c81d5 --- /dev/null +++ b/mifosng-db/patches/11-ddl_group_level_col_name_changed.sql @@ -0,0 +1 @@ +ALTER TABLE m_group_level CHANGE `is_super_parent` `super_parent` TINYINT(1) NOT NULL; diff --git a/mifosng-db/patches/11-ddl_group_level_table.sql b/mifosng-db/patches/11-ddl_group_level_table.sql index 68ba20f0d..280cb1988 100644 --- a/mifosng-db/patches/11-ddl_group_level_table.sql +++ b/mifosng-db/patches/11-ddl_group_level_table.sql @@ -1,13 +1,13 @@ CREATE TABLE `m_group_level` ( - `id` INT(11) NOT NULL AUTO_INCREMENT, - `parent_id` INT(11) NULL DEFAULT NULL, - `is_super_parent` TINYINT(1) NOT NULL, - `level_name` VARCHAR(100) NOT NULL, - `recursable` TINYINT(1) NOT NULL, - `can_have_clients` TINYINT(1) NOT NULL, - PRIMARY KEY (`id`), - INDEX `Parent_levelId_reference` (`parent_id`), - CONSTRAINT `Parent_levelId_reference` FOREIGN KEY (`parent_id`) REFERENCES `m_group_level` (`id`) +`id` INT(11) NOT NULL AUTO_INCREMENT, +`parent_id` INT(11) NULL DEFAULT NULL, +`is_super_parent` TINYINT(1) NOT NULL, +`level_name` VARCHAR(100) NOT NULL, +`recursable` TINYINT(1) NOT NULL, +`can_have_clients` TINYINT(1) NOT NULL, +PRIMARY KEY (`id`), +INDEX `Parent_levelId_reference` (`parent_id`), +CONSTRAINT `Parent_levelId_reference` FOREIGN KEY (`parent_id`) REFERENCES `m_group_level` (`id`) ) COLLATE='utf8_general_ci' ENGINE=InnoDB; @@ -19,8 +19,8 @@ ALTER TABLE m_group DROP FOREIGN KEY `FK_m_group_m_staff`; ALTER TABLE m_group CHANGE `loan_officer_id` `staff_id` BIGINT(20) NULL DEFAULT NULL; ALTER TABLE m_group ADD COLUMN `level_Id` INT(11) NOT NULL AFTER `office_id`; ALTER TABLE m_group ADD COLUMN `parent_id` BIGINT(20) NULL DEFAULT NULL AFTER `level_Id`; -ALTER TABLE m_group ADD COLUMN `hierarchy` VARCHAR(100) NULL DEFAULT NULL AFTER `parent_id`; +ALTER TABLE m_group ADD COLUMN `hierarchy` VARCHAR(100) NULL DEFAULT NULL AFTER `parent_id`; ALTER TABLE m_group ADD CONSTRAINT `FK_m_group_m_staff` FOREIGN KEY (`staff_id`) REFERENCES `m_staff` (`id`); ALTER TABLE m_group ADD CONSTRAINT `Parent_Id_reference` FOREIGN KEY (`parent_id`) REFERENCES `m_group` (`id`); UPDATE m_group mg SET mg.level_Id = 1; -ALTER TABLE m_group ADD CONSTRAINT `FK_m_group_level` FOREIGN KEY (`level_Id`) REFERENCES `m_group_level` (`id`); +ALTER TABLE m_group ADD CONSTRAINT `FK_m_group_level` FOREIGN KEY (`level_Id`) REFERENCES `m_group_level` (`id`); \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/api/GroupsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/api/GroupsApiResource.java index 081ca06e3..55e6cc885 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/api/GroupsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/api/GroupsApiResource.java @@ -37,6 +37,7 @@ import org.mifosplatform.portfolio.client.service.ClientReadPlatformService; import org.mifosplatform.portfolio.group.command.GroupCommand; import org.mifosplatform.portfolio.group.data.GroupAccountSummaryCollectionData; import org.mifosplatform.portfolio.group.data.GroupData; +import org.mifosplatform.portfolio.group.data.GroupLookupData; import org.mifosplatform.portfolio.group.service.GroupReadPlatformService; import org.mifosplatform.portfolio.group.service.GroupWritePlatformService; import org.mifosplatform.portfolio.savingsaccount.PortfolioApiDataConversionService; @@ -50,7 +51,7 @@ import org.springframework.stereotype.Component; public class GroupsApiResource { private static final Set GROUP_DATA_PARAMETERS = new HashSet(Arrays.asList("id", "officeId", "name", "externalId", - "clientMembers", "allowedClients", "allowedOffices")); + "clientMembers", "allowedClients", "allowedOffices" , "allowedParentGroups" ,"groupLevel")); private final PlatformSecurityContext context; private final GroupReadPlatformService groupReadPlatformService; @@ -113,8 +114,9 @@ public class GroupsApiResource { final Collection clientMembers = this.groupReadPlatformService.retrieveClientMembers(groupId); Collection availableClients = null; Collection allowedOffices = null; + Collection allowedParentGroups = null; - group = new GroupData(group, clientMembers, availableClients, allowedOffices); + group = new GroupData(group, clientMembers, availableClients, allowedOffices , allowedParentGroups , null); boolean template = ApiParameterHelper.template(uriInfo.getQueryParameters()); if (template) { @@ -128,7 +130,7 @@ public class GroupsApiResource { allowedOffices = officeReadPlatformService.retrieveAllOfficesForLookup(); - group = new GroupData(group, group.clientMembers(), availableClients, allowedOffices); + group = new GroupData(group, group.clientMembers(), availableClients, allowedOffices , allowedParentGroups ,null); } final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); @@ -139,15 +141,16 @@ public class GroupsApiResource { @Path("template") @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) - public String newGroupDetails(@Context final UriInfo uriInfo, @QueryParam("officeId") final Long officeId) { + public String newGroupDetails(@Context final UriInfo uriInfo, @QueryParam("officeId") final Long officeId, + @QueryParam("levelId") final Long levelId) { context.authenticatedUser().validateHasReadPermission("GROUP"); - GroupData groupTemplateData; - if (officeId != null) { - groupTemplateData = this.groupReadPlatformService.retrieveNewGroupDetails(officeId); - } else { - groupTemplateData = this.groupReadPlatformService.retrieveNewGroupDetails(context.authenticatedUser().getOffice().getId()); + GroupData groupTemplateData = null; + if (officeId != null && levelId != null) { + groupTemplateData = this.groupReadPlatformService.retrieveNewGroupDetails(officeId, levelId); + } else if (levelId != null) { + groupTemplateData = this.groupReadPlatformService.retrieveNewGroupDetails(context.authenticatedUser().getOffice().getId(), levelId); } final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/command/GroupCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/command/GroupCommand.java index d4640e72f..1e8c93718 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/command/GroupCommand.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/command/GroupCommand.java @@ -14,16 +14,20 @@ public class GroupCommand { private final String name; private final Long officeId; private final Long loanOfficerId; + private final Long parentId; + private final Long levelId; private final String[] clientMembers; private final Set modifiedParameters; public GroupCommand(Set modifiedParameters, final Long id, final String externalId, final String name, - final Long officeId, final Long loanOfficerId, String[] clientMembers) { + final Long officeId, final Long loanOfficerId, String[] clientMembers , final Long parentId ,final Long levelId) { this.id = id; this.officeId = officeId; this.loanOfficerId = loanOfficerId; + this.parentId = parentId; + this.levelId = levelId; this.externalId = externalId; this.name = name; this.clientMembers = clientMembers; @@ -35,6 +39,14 @@ public class GroupCommand { return officeId; } + public Long getParentId() { + return parentId; + } + + public Long getLevelId() { + return levelId; + } + public Long getLoanOfficeId() { return loanOfficerId; } @@ -59,6 +71,14 @@ public class GroupCommand { return this.modifiedParameters.contains("officeId"); } + public boolean isParentIdChanged() { + return this.modifiedParameters.contains("parentId"); + } + + public boolean isLevelIdChanged() { + return this.modifiedParameters.contains("levelId"); + } + public boolean isLoanOfficerChanged() { return this.modifiedParameters.contains("loanOfficerId"); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/command/GroupCommandValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/command/GroupCommandValidator.java index 843bb8241..85a33a75a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/command/GroupCommandValidator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/command/GroupCommandValidator.java @@ -28,10 +28,8 @@ public class GroupCommandValidator { baseDataValidator.reset().parameter("name").value(command.getName()).notBlank(); baseDataValidator.reset().parameter("externalId").value(command.getExternalId()).ignoreIfNull().notExceedingLengthOf(100); - - baseDataValidator.reset().parameter("clientMembers").value(command.getClientMembers()).arrayNotEmpty(); - baseDataValidator.reset().parameter("officeId").value(command.getOfficeId()).notNull().integerGreaterThanZero(); + baseDataValidator.reset().parameter("levelId").value(command.getLevelId()).notNull().integerGreaterThanZero(); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/data/GroupData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/data/GroupData.java index 19eca30c3..703899801 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/data/GroupData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/data/GroupData.java @@ -9,86 +9,93 @@ import java.util.Collection; import org.mifosplatform.organisation.office.data.OfficeLookup; import org.mifosplatform.portfolio.client.data.ClientLookup; +import org.mifosplatform.portfolio.group.domain.GroupLevel; /** * Immutable data object representing groups. */ public class GroupData { - private final Long id; - private final String name; - private final String externalId; - private final Long officeId; - private final String officeName; + private final Long id; + private final String name; + private final String externalId; + private final Long officeId; + private final String officeName; + private final GroupLevelData groupLevelData; - private final Collection clientMembers; - @SuppressWarnings("unused") - private final Collection allowedClients; - @SuppressWarnings("unused") - private final Collection allowedOffices; + private final Collection clientMembers; + @SuppressWarnings("unused") + private final Collection allowedClients; + @SuppressWarnings("unused") + private final Collection allowedOffices; + @SuppressWarnings("unused") + private final Collection allowedParentGroups; - public GroupData( - final Long id, - final Long officeId, - final String officeName, - final String name, - final String externalId) { - this.id = id; - this.officeId = officeId; - this.officeName = officeName; - this.name = name; - this.externalId = externalId; + public GroupData(final Long id, final Long officeId, final String officeName, final String name, final String externalId ) { + this.id = id; + this.officeId = officeId; + this.officeName = officeName; + this.name = name; + this.externalId = externalId; - this.clientMembers = null; - this.allowedClients = null; - this.allowedOffices = null; - } + this.groupLevelData = null; + this.clientMembers = null; + this.allowedClients = null; + this.allowedOffices = null; + this.allowedParentGroups = null; + } - public GroupData(final GroupData group, final Collection clientMembers, final Collection allowedClients, - final Collection allowedOffices) { - this.id = group.getId(); - this.officeId = group.getOfficeId(); - this.officeName = group.getOfficeName(); - this.name = group.getName(); - this.externalId = group.getExternalId(); - - this.clientMembers = clientMembers; - this.allowedClients = allowedClients; - this.allowedOffices = allowedOffices; - } - - public GroupData(final Long officeId, final Collection allowedClients, final Collection allowedOffices) { - this.id = null; - this.officeId = officeId; - this.officeName = null; - this.name = null; - this.externalId = null; - this.clientMembers = null; - this.allowedClients = allowedClients; - this.allowedOffices = allowedOffices; - } - - public Long getId() { - return id; - } + public GroupData(final GroupData group, final Collection clientMembers, final Collection allowedClients, + final Collection allowedOffices, final Collection allowedParentGroups , final GroupLevelData groupLevelData) { + this.id = group.getId(); + this.officeId = group.getOfficeId(); + this.officeName = group.getOfficeName(); + this.name = group.getName(); + this.externalId = group.getExternalId(); - public String getName() { - return name; - } + this.groupLevelData = groupLevelData; + this.clientMembers = clientMembers; + this.allowedClients = allowedClients; + this.allowedOffices = allowedOffices; + this.allowedParentGroups = allowedParentGroups; + } - public String getExternalId() { - return externalId; - } + public GroupData(final Long officeId, final Collection allowedClients, final Collection allowedOffices, + final Collection allowedParentGroups , final GroupLevelData groupLevelData ) { + this.id = null; + this.officeId = officeId; + this.officeName = null; + this.name = null; + this.externalId = null; + this.clientMembers = null; + this.groupLevelData = groupLevelData; + this.allowedClients = allowedClients; + this.allowedOffices = allowedOffices; + this.allowedParentGroups = allowedParentGroups; - public Long getOfficeId() { - return officeId; - } + } - public String getOfficeName() { - return officeName; - } + public Long getId() { + return id; + } - public Collection clientMembers() { - return this.clientMembers; - } + public String getName() { + return name; + } + + public String getExternalId() { + return externalId; + } + + public Long getOfficeId() { + return officeId; + } + + public String getOfficeName() { + return officeName; + } + + public Collection clientMembers() { + return this.clientMembers; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/data/GroupLevelData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/data/GroupLevelData.java new file mode 100644 index 000000000..a192ee971 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/data/GroupLevelData.java @@ -0,0 +1,59 @@ +/** + * 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.portfolio.group.data; + +/** + * Immutable data object representing groups. + */ +public class GroupLevelData { + + private final Long levelId; + private final Long parentLevelId; + private final String levelName; + private final boolean superParent; + private final boolean recursable; + private final boolean canHaveClients; + + public GroupLevelData(Long levelId, Long parentLevelId, String levelName, boolean superParent, boolean recursable, + boolean canHaveClients) { + this.levelId = levelId; + this.parentLevelId = parentLevelId; + this.levelName = levelName; + this.superParent = superParent; + this.recursable = recursable; + this.canHaveClients = canHaveClients; + } + + public Long getLevelId() { + return this.levelId; + } + + + public Long getParentLevelId() { + return this.parentLevelId; + } + + + public String getLevelName() { + return this.levelName; + } + + + public boolean isSuperParent() { + return this.superParent; + } + + + public boolean isRecursable() { + return this.recursable; + } + + + public boolean isCanHaveClients() { + return this.canHaveClients; + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/data/GroupLookupData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/data/GroupLookupData.java new file mode 100644 index 000000000..34376880f --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/data/GroupLookupData.java @@ -0,0 +1,28 @@ +/** + * 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.portfolio.group.data; + +/** + * Immutable data object representing groups. + */ +public class GroupLookupData { + + private final Long id; + private final String name; + + public GroupLookupData(final Long id, final String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/domain/Group.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/domain/Group.java index ad4240df3..573e2f732 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/domain/Group.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/domain/Group.java @@ -6,14 +6,18 @@ package org.mifosplatform.portfolio.group.domain; import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; import java.util.Set; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; import javax.persistence.Table; import org.apache.commons.lang.StringUtils; @@ -27,6 +31,14 @@ import org.springframework.data.jpa.domain.AbstractPersistable; @Table(name = "m_group") public class Group extends AbstractPersistable { + @OneToMany(fetch = FetchType.EAGER) + @JoinColumn(name = "parent_id") + private final List children = new LinkedList(); + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "parent_id") + private Group parent; + @ManyToOne @JoinColumn(name = "office_id", nullable = false) private Office office; @@ -34,6 +46,12 @@ public class Group extends AbstractPersistable { @ManyToOne @JoinColumn(name = "staff_id", nullable = true) private Staff loanOfficer; + + @Column(name = "level_id", nullable = false) + private Long levelId; + + @Column(name = "hierarchy", length = 100) + private String hierarchy; @Column(name = "name", length = 100, unique = true) private String name; @@ -54,13 +72,20 @@ public class Group extends AbstractPersistable { this.clientMembers = new HashSet(); } - public static Group newGroup(final Office office, final Staff loanOfficer , final String name, final String externalId, final Set clientMembers) { - return new Group(office, loanOfficer , name, externalId, clientMembers); + public static Group newGroup(final Office office, final Staff loanOfficer , final Group parent ,final long levelId , final String name, final String externalId, final Set clientMembers) { + return new Group(office, loanOfficer , parent , levelId , name, externalId, clientMembers); } - public Group(final Office office, final Staff loanOfficer , final String name, final String externalId, final Set clientMembers) { + public Group(final Office office, final Staff loanOfficer , final Group parent ,final long levelId , final String name, final String externalId, final Set clientMembers) { this.office = office; this.loanOfficer = loanOfficer; + this.levelId =levelId; + this.parent = parent; + + if (parent != null) { + this.parent.addChild(this); + } + if (StringUtils.isNotBlank(name)) { this.name = name.trim(); } else { @@ -76,6 +101,10 @@ public class Group extends AbstractPersistable { } } + private void addChild(final Group group) { + this.children.add(group); + } + public Long getOfficeId() { return this.office.getId(); } @@ -141,5 +170,18 @@ public class Group extends AbstractPersistable { public boolean isDeleted() { return deleted; } + + public void generateHierarchy() { + + if (parent != null) { + this.hierarchy = this.parent.hierarchyOf(this.getId()); + } else { + this.hierarchy = "."; + } + } + + private String hierarchyOf(Long id) { + return this.hierarchy + id.toString() + "."; + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/domain/GroupLevel.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/domain/GroupLevel.java index 3f7eba7c9..ec9b5980b 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/domain/GroupLevel.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/domain/GroupLevel.java @@ -18,7 +18,7 @@ public class GroupLevel extends AbstractPersistable { @Column(name = "parent_id") private final Long parentId; - @Column(name = "is_super_parent", nullable = false) + @Column(name = "super_parent", nullable = false) private final boolean isSuperParent; @Column(name = "level_name", nullable = false, length = 100, unique = true) diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/domain/GroupRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/domain/GroupRepository.java index 5443fa40d..f99bdabbf 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/domain/GroupRepository.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/domain/GroupRepository.java @@ -9,5 +9,5 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; public interface GroupRepository extends JpaRepository, JpaSpecificationExecutor { - // no behaviour added + } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/exception/GroupLevelNotFoundException.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/exception/GroupLevelNotFoundException.java new file mode 100644 index 000000000..945fe079f --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/exception/GroupLevelNotFoundException.java @@ -0,0 +1,19 @@ +/** + * 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.portfolio.group.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; + +/** + * A {@link RuntimeException} thrown when group resources are not found. + */ +public class GroupLevelNotFoundException extends AbstractPlatformResourceNotFoundException { + + public GroupLevelNotFoundException(Long id){ + super("error.msg.group.level.id.invalid", "Group level with identifier " + id + " does not exist", id); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformService.java index 2548d2f05..793723e91 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformService.java @@ -11,6 +11,8 @@ import org.mifosplatform.portfolio.client.data.ClientLookup; import org.mifosplatform.portfolio.group.data.GroupAccountSummaryCollectionData; import org.mifosplatform.portfolio.group.data.GroupAccountSummaryData; import org.mifosplatform.portfolio.group.data.GroupData; +import org.mifosplatform.portfolio.group.data.GroupLevelData; +import org.mifosplatform.portfolio.group.data.GroupLookupData; public interface GroupReadPlatformService { @@ -18,11 +20,15 @@ public interface GroupReadPlatformService { GroupData retrieveGroup(Long groupId); - GroupData retrieveNewGroupDetails(Long officeId); + GroupData retrieveNewGroupDetails(Long officeId , Long levelId); Collection retrieveClientMembers(Long groupId); GroupAccountSummaryCollectionData retrieveGroupAccountDetails(Long groupId); Collection retrieveGroupLoanAccountsByLoanOfficerId(Long groupId, Long loanOfficerId); + + Collection retrieveAllGroupsbyOfficeIdAndLevelId(Long officeId , Long levelId); + + GroupLevelData retrieveGroupLevelDetails(Long levelId); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformServiceImpl.java index 5b483ad3a..9370035f9 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformServiceImpl.java @@ -23,6 +23,9 @@ import org.mifosplatform.portfolio.client.service.LoanStatusMapper; import org.mifosplatform.portfolio.group.data.GroupAccountSummaryCollectionData; import org.mifosplatform.portfolio.group.data.GroupAccountSummaryData; import org.mifosplatform.portfolio.group.data.GroupData; +import org.mifosplatform.portfolio.group.data.GroupLevelData; +import org.mifosplatform.portfolio.group.data.GroupLookupData; +import org.mifosplatform.portfolio.group.exception.GroupLevelNotFoundException; import org.mifosplatform.portfolio.group.exception.GroupNotFoundException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.EmptyResultDataAccessException; @@ -37,10 +40,10 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService { private final PlatformSecurityContext context; private final ClientReadPlatformService clientReadPlatformService; private final OfficeReadPlatformService officeReadPlatformService; - + @Autowired public GroupReadPlatformServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource, - ClientReadPlatformService clientReadPlatformService, final OfficeReadPlatformService officeReadPlatformService) { + ClientReadPlatformService clientReadPlatformService, final OfficeReadPlatformService officeReadPlatformService ) { this.context = context; this.jdbcTemplate = new JdbcTemplate(dataSource); this.clientReadPlatformService = clientReadPlatformService; @@ -52,7 +55,7 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService { this.context.authenticatedUser(); - GroupMapper rm = new GroupMapper(); + GroupDataMapper rm = new GroupDataMapper(); String sql = "select " + rm.groupSchema() + " where g.is_deleted=0"; @@ -69,7 +72,7 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService { try { this.context.authenticatedUser(); - GroupMapper rm = new GroupMapper(); + GroupDataMapper rm = new GroupDataMapper(); String sql = "select " + rm.groupSchema() + " where g.id = ? and g.is_deleted=0"; @@ -80,17 +83,68 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService { } @Override - public GroupData retrieveNewGroupDetails(final Long officeId) { + public Collection retrieveAllGroupsbyOfficeIdAndLevelId(final Long officeId, final Long levelId) { - List allowedClients = new ArrayList( - this.clientReadPlatformService.retrieveAllIndividualClientsForLookupByOfficeId(officeId)); + try { + this.context.authenticatedUser(); - List allowedOffices = new ArrayList(officeReadPlatformService.retrieveAllOfficesForLookup()); + GroupLookupMapper rm = new GroupLookupMapper(); - return new GroupData(officeId, allowedClients, allowedOffices); + String sql = "select " + rm.groupLookupSchema() + " where g.office_id = ? and level_id = ? and g.is_deleted=0"; + + return this.jdbcTemplate.query(sql, rm, new Object[] { officeId, levelId }); + + } catch (EmptyResultDataAccessException e) { + + // TODO need throw proper exception + throw new GroupNotFoundException(officeId); + } } - private static final class GroupMapper implements RowMapper { + @Override + public GroupLevelData retrieveGroupLevelDetails(final Long levelId) { + + try { + this.context.authenticatedUser(); + + GroupLevelDataMapper rm = new GroupLevelDataMapper(); + + String sql = "select " + rm.groupLevelSchema() + " where gl.id = ? "; + + return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { levelId }); + + } catch (EmptyResultDataAccessException e) { + throw new GroupLevelNotFoundException(levelId); + } + } + + @Override + public GroupData retrieveNewGroupDetails(final Long officeId , final Long levelId) { + + GroupLevelData groupLevelData = this.retrieveGroupLevelDetails(levelId); + + if (groupLevelData == null) { throw new GroupLevelNotFoundException(levelId); } + + List allowedClients = null; + + if (groupLevelData.isCanHaveClients()) { + allowedClients = new ArrayList( + this.clientReadPlatformService.retrieveAllIndividualClientsForLookupByOfficeId(officeId)); + } + + List allowedOffices = new ArrayList(officeReadPlatformService.retrieveAllOfficesForLookup()); + + List allowedParentGroups = null; + + if(groupLevelData.getParentLevelId() != null){ + allowedParentGroups = new ArrayList(this.retrieveAllGroupsbyOfficeIdAndLevelId(officeId , groupLevelData.getParentLevelId())); + } + + + return new GroupData(officeId, allowedClients, allowedOffices , allowedParentGroups , groupLevelData); + } + + private static final class GroupDataMapper implements RowMapper { public String groupSchema() { return "g.office_id as officeId, o.name as officeName, g.id as id, g.external_id as externalId, " @@ -111,6 +165,45 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService { } } + + private static final class GroupLookupMapper implements RowMapper { + + public String groupLookupSchema() { + return "g.id as id, g.name as name from m_group g"; + } + + @Override + public GroupLookupData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException { + + Long id = rs.getLong("id"); + String name = rs.getString("name"); + + return new GroupLookupData(id, name); + } + + } + + private static final class GroupLevelDataMapper implements RowMapper { + + public String groupLevelSchema() { + return "gl.id as id, gl.parent_id as parentLevelId , gl.level_name as levelName , gl.super_parent as superParent ," + + " gl.recursable as recursable , gl.can_have_clients as canHaveClients from m_group_level gl"; + } + + @Override + public GroupLevelData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException { + + Long levelId = rs.getLong("id"); + Long parentLevelId = rs.getLong("parentLevelId"); + String levelName = rs.getString("levelName"); + boolean superParent = rs.getBoolean("superParent"); + boolean recursable = rs.getBoolean("recursable"); + boolean canHaveClients = rs.getBoolean("canHaveClients"); + + return new GroupLevelData(levelId, parentLevelId, levelName, superParent, recursable, canHaveClients); + } + + } @Override public Collection retrieveClientMembers(Long groupId) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupWritePlatformServiceJpaRepositoryImpl.java index 7e53fc3f0..4b2e41777 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupWritePlatformServiceJpaRepositoryImpl.java @@ -71,21 +71,49 @@ public class GroupWritePlatformServiceJpaRepositoryImpl implements GroupWritePla final Office groupOffice = this.officeRepository.findOne(command.getOfficeId()); + if (groupOffice == null) { throw new OfficeNotFoundException(command.getOfficeId()); } + Staff loanOfficer = null; final Long loanOfficerId = command.getLoanOfficeId(); - if (groupOffice == null) { throw new OfficeNotFoundException(command.getOfficeId()); } - + /** + * Validate the loan officer is present in the given office or not + */ if (loanOfficerId != null) { loanOfficer = this.staffRepository.findByOffice(loanOfficerId, command.getOfficeId()); if (loanOfficer == null) { throw new StaffNotFoundException(loanOfficerId); } } + final Long parentId = command.getParentId(); + Group parent = null; + + /** + * Validate the parent group to check it is present. + */ + + if (parentId != null) { + parent = this.groupRepository.findOne(parentId); + if (parent == null) { throw new GroupNotFoundException(parentId); } + } + + /** + * Need to validate level is immediate child level of the Parent group's level + */ + // TODO level validation + + final Long levelId = command.getLevelId(); + final Set clientMembers = assembleSetOfClients(command); - final Group newGroup = Group.newGroup(groupOffice, loanOfficer, command.getName(), command.getExternalId(), clientMembers); + final Group newGroup = Group.newGroup(groupOffice, loanOfficer, parent , levelId , command.getName(), command.getExternalId(), clientMembers); + // pre save to generate id for use in group hierarchy + this.groupRepository.save(newGroup); + + newGroup.generateHierarchy(); + this.groupRepository.saveAndFlush(newGroup); + return new CommandProcessingResult(newGroup.getId()); } catch (final DataIntegrityViolationException dve) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/PortfolioApiDataConversionServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/PortfolioApiDataConversionServiceImpl.java index 99eece62a..625b0aab6 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/PortfolioApiDataConversionServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/PortfolioApiDataConversionServiceImpl.java @@ -68,18 +68,20 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo final Type typeOfMap = new TypeToken>() {}.getType(); final Map requestMap = gsonConverter.fromJson(json, typeOfMap); - final Set supportedParams = new HashSet(Arrays.asList("name", "officeId", "loanOfficerId" ,"externalId", "clientMembers")); + final Set supportedParams = new HashSet(Arrays.asList("name", "officeId", "levelId", "parentId", "loanOfficerId", + "externalId", "clientMembers")); checkForUnsupportedParameters(requestMap, supportedParams); final Set modifiedParameters = new HashSet(); + final String name = extractStringParameter("name", requestMap, modifiedParameters); final Long officeId = extractLongParameter("officeId", requestMap, modifiedParameters); + final Long levelId = extractLongParameter("levelId", requestMap, modifiedParameters); + final Long parentId = extractLongParameter("parentId", requestMap, modifiedParameters); final Long loanOfficerId = extractLongParameter("loanOfficerId", requestMap, modifiedParameters); final String externalId = extractStringParameter("externalId", requestMap, modifiedParameters); - final String name = extractStringParameter("name", requestMap, modifiedParameters); - // check array final JsonParser parser = new JsonParser(); String[] clientMembers = null; @@ -95,9 +97,8 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo } } } - // - return new GroupCommand(modifiedParameters, resourceIdentifier, externalId, name, officeId, loanOfficerId , clientMembers); + return new GroupCommand(modifiedParameters, resourceIdentifier, externalId, name, officeId, loanOfficerId , clientMembers ,parentId ,levelId); } private void checkForUnsupportedParameters(Map requestMap, Set supportedParams) {