Last active
April 1, 2017 17:23
-
-
Save Walletau/c7db07d9e8c9e46f735a6332cdb94f78 to your computer and use it in GitHub Desktop.
RH Snip3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/////////////// | |
//Hierarchy tree sorter | |
/////////////// | |
//Initialising process to recalculate hierarchy for given accounts | |
//Any member of the account hierarchy can be identified in order to intiate a complete recalculation | |
public static void processAccountHierarchyMembership(Set<Id> targetedAccountsIds) { | |
//Given that the hierarchy code requires the top parent record, we first obtain the master parent records | |
Set<Id> topIds = getTopAccountIds(targetedAccountsIds); | |
List<Account> topAccounts = new List<Account>(); | |
for (Account acc: [ | |
select id, | |
name, | |
PublicGroupId__c, | |
ChildrenPublicGroupId__c, | |
ParentPublicGroupId__c | |
from Account | |
where id IN :topIds | |
]) | |
topAccounts.add(acc); | |
Map<Id, HierarchyNode> accMap = getAccountHierarchiesQuick(topAccounts); | |
memberManagement(accMap); | |
} | |
//Recursive method loop to return a Set of Accounts identifying all children accounts for a given set | |
private static Set<Id> traverseChildren(List<HierarchyNode> children, Map<Id, HierarchyNode> nodes) { | |
Set<Id> acc_ids = new Set<Id>(); | |
for (HierarchyNode referenceNode : children) { | |
acc_ids.add(referenceNode.node.id); | |
acc_ids.addAll(traverseChildren(referenceNode.children, nodes)); | |
} | |
return acc_ids; | |
} | |
//Given a list of accounts and their direct parent Ids, create new nodes for the children accounts and add them to the | |
//children of the parent accounts | |
public static void addChildren(List<Account> accs, Map<Id, HierarchyNode> nodes, Set<Id> parentAccountIds) { | |
for (Account acc : accs) { | |
HierarchyNode referenceNode = nodes.get(acc.ParentId); | |
HierarchyNode newNode = new HierarchyNode(acc, referenceNode); | |
nodes.put(acc.id, newNode); | |
if (referenceNode != null) { | |
referenceNode.children.add(newNode); | |
} | |
if (parentAccountIds != null) { | |
parentAccountIds.add(acc.id); | |
} | |
} | |
} | |
//Initialisation of the Account Hierarchy generator, when the source is an account list | |
//Will only return a hierarchy of the accounts at the level or below of specified list | |
public static Map<Id, HierarchyNode> getAccountHierarchiesQuick(List<Account> top_accts) { | |
Set<Id> parentAccountIds = new Set<Id>(); | |
for (Account a : top_accts) { | |
parentAccountIds.add(a.Id); | |
} | |
return getAccountHierarchiesQuick(parentAccountIds, top_accts); | |
} | |
//Recursive method loop to find the master parent accounts for any accounts submitted to the testMethod | |
public static Set<Id> getTopAccountIds(Set<Id> accountsTargeted) { | |
Set<Id> topAccountIds = new Set<Id>(); | |
Set<Id> recursivelyTargetedAccountIds = new Set<Id>(); | |
for (Account targetedAccount : [ | |
SELECT Id, | |
Name, | |
ChildrenPublicGroupId__c, | |
PublicGroupId__c, | |
ParentPublicGroupId__c, | |
ParentID, | |
Parent.ParentID, | |
Parent.Parent.ParentID, | |
Parent.Parent.Parent.ParentID, | |
RecordTypeId | |
FROM Account | |
WHERE Id IN :accountsTargeted | |
]) { | |
if (targetedAccount.Parent.Parent.Parent.ParentID != null) { | |
recursivelyTargetedAccountIds.add(targetedAccount.Parent.Parent.Parent.ParentID); | |
} else if (targetedAccount.Parent.Parent.ParentId != null) { | |
topAccountIds.add(targetedAccount.Parent.Parent.ParentId); | |
} else if (targetedAccount.Parent.ParentId != null) { | |
topAccountIds.add(targetedAccount.Parent.ParentId); | |
} else if (targetedAccount.ParentId != null) { | |
topAccountIds.add(targetedAccount.ParentId); | |
} else { | |
topAccountIds.add(targetedAccount.Id); | |
} | |
} | |
if (!recursivelyTargetedAccountIds.isEmpty()) { | |
topAccountIds.addAll(getTopAccountIds(recursivelyTargetedAccountIds)); | |
} | |
return topAccountIds; | |
} | |
public static Map<Id, HierarchyNode> getAccountHierarchiesQuick(Set<Id> top_acct_ids, List<Account> top_accs) { | |
Map<Id, HierarchyNode> nodes = new Map<Id, HierarchyNode>(); | |
Set<Id> parentAccountIds = top_acct_ids; | |
for (Account top_acc : top_accs) { | |
HierarchyNode newNode = new HierarchyNode(top_acc); | |
nodes.put(top_acc.id, newNode); | |
} | |
while (parentAccountIds.size() > 0) { | |
Map<Id, Account> subordinate_accounts = | |
new Map<Id, Account>([ | |
SELECT Id, | |
Name, | |
ChildrenPublicGroupId__c, | |
PublicGroupId__c, | |
ParentPublicGroupId__c, | |
Parent.ParentID, | |
Parent.Parent.ParentID, | |
Parent.Parent.Parent.ParentID, | |
RecordTypeId, ( | |
SELECT Id | |
FROM Contacts | |
) | |
FROM Account | |
WHERE (ParentId IN :parentAccountIds) | |
OR | |
(Parent.ParentId IN :parentAccountIds) | |
OR | |
(Parent.Parent.ParentId IN :parentAccountIds) | |
OR | |
(Parent.Parent.Parent.ParentId IN :parentAccountIds) | |
]); | |
List<Account> level1_accs = new List<Account>(); | |
List<Account> level2_accs = new List<Account>(); | |
List<Account> level3_accs = new List<Account>(); | |
List<Account> level4_accs = new List<Account>(); | |
// Split accounts in levels | |
for (Account acc : subordinate_accounts.values()) { | |
if (acc.ParentId != null) { | |
if (parentAccountIds.contains(acc.ParentId)) { | |
level1_accs.add(acc); | |
} else if (acc.Parent.ParentId != null) { | |
if (parentAccountIds.contains(acc.Parent.ParentId)) { | |
level2_accs.add(acc); | |
} else if (acc.Parent.Parent.ParentId != null) { | |
if (parentAccountIds.contains(acc.Parent.Parent.ParentId)) { | |
level3_accs.add(acc); | |
} else if (acc.Parent.Parent.Parent.ParentId != null) { | |
if (parentAccountIds.contains(acc.Parent.Parent.Parent.ParentId)) { | |
level4_accs.add(acc); | |
} | |
} | |
} | |
} | |
} | |
} | |
Set<Id> next_parentAccountIds = new Set<Id>(); | |
// Add children on all levels found, one level at a time | |
addChildren(level1_accs, nodes, null); | |
addChildren(level2_accs, nodes, null); | |
addChildren(level3_accs, nodes, null); | |
addChildren(level4_accs, nodes, next_parentAccountIds); | |
// Use lowest level of account ids for next SOQL query | |
parentAccountIds = next_parentAccountIds; | |
} | |
return nodes; | |
} | |
//process individual membership per public group of each account | |
public static void memberManagement(Map<Id, HierarchyNode> nodes) { | |
Map<Id, Id> childPublicGroupIdToAccountId = new Map<Id, Id>(); | |
Map<Id, Id> primaryPublicGroupIdToAccountId = new Map<Id, Id>(); | |
Map<Id, Id> parentPublicGroupIdToAccountId = new Map<Id, Id>(); | |
List<GroupMember> groupMembersToDelete = new List<GroupMember>(); | |
List<GroupMember> groupMembersToInsert = new List<GroupMember>(); | |
//obtain complete list of public groups to process | |
for (HierarchyNode hierarchyNode : nodes.values()) { | |
childPublicGroupIdToAccountId.put(hierarchyNode.node.ChildrenPublicGroupId__c, hierarchyNode.node.Id); | |
primaryPublicGroupIdToAccountId.put(hierarchyNode.node.PublicGroupId__c, hierarchyNode.node.Id); | |
parentPublicGroupIdToAccountId.put(hierarchyNode.node.ParentPublicGroupId__c, hierarchyNode.node.Id); | |
} | |
Set<Id> targetedPublicGroupIds = new Set<Id>(); | |
targetedPublicGroupIds.addAll(childPublicGroupIdToAccountId.keySet()); | |
targetedPublicGroupIds.addAll(primaryPublicGroupIdToAccountId.keySet()); | |
targetedPublicGroupIds.addAll(parentPublicGroupIdToAccountId.keySet()); | |
//search all account related roles for role mapping | |
Map<Id, UserRole> accountRelatedRoles = new Map<Id, UserRole>([ | |
SELECT Id, | |
PortalAccountId | |
FROM UserRole | |
WHERE PortalAccountId IN :primaryPublicGroupIdToAccountId.values() | |
]); | |
Map<Id, Id> accountIdToPrimaryRoleGroupId = new Map<Id, Id>(); | |
// | |
Map<Id, Group> groupIdToGroup = new map<Id, Group>([ | |
SELECT Id, | |
Type, | |
RelatedId, ( | |
SELECT Id, | |
UserOrGroupId, | |
GroupId | |
FROM GroupMembers | |
) | |
FROM Group | |
WHERE Id IN :targetedPublicGroupIds | |
OR RelatedId IN :accountRelatedRoles.keySet() | |
]); | |
// | |
for (Id groupId : groupIdToGroup.keySet()) { | |
Group targetedGroup = groupIdToGroup.get(groupId); | |
if (targetedGroup.Type == 'Role') { | |
if (accountRelatedRoles.containsKey(targetedGroup.RelatedId)) | |
accountIdToPrimaryRoleGroupId.put(accountRelatedRoles.get(targetedGroup.RelatedId).PortalAccountId, groupId); | |
} | |
} | |
// | |
Set<Id> groupIdsForFinalMembershipRecalc = new Set<Id>(); | |
for (Id groupId : groupIdToGroup.keySet()) { | |
Group targetedGroup = groupIdToGroup.get(groupId); | |
if (childPublicGroupIdToAccountId.containsKey(groupId)) { | |
//all children group and the associated primary group | |
HierarchyNode targetedNode = nodes.get(childPublicGroupIdToAccountId.get(groupId)); | |
Set<Id> allChildNodes = traverseChildren(targetedNode.children, nodes); | |
Set<Id> childPublicGroupsToBePresent = new Set<Id>(); | |
for (Id childNodeId : allChildNodes) | |
childPublicGroupsToBePresent.add(nodes.get(childNodeId).node.PublicGroupId__c); | |
Map<Id, Id> memberDetailIdToGroupMemberId = new Map<Id, Id>(); | |
for (GroupMember groupMember : groupIdToGroup.get(groupId).GroupMembers) | |
memberDetailIdToGroupMemberId.put(groupMember.UserOrGroupId, groupMember.Id); | |
Map<String, Set<Id>> comparedSet = compareSets(childPublicGroupsToBePresent, memberDetailIdToGroupMemberId.keySet()); | |
if (comparedSet.containsKey('In_First_Set')) { | |
for (Id groupMemberPublicGroup: comparedSet.get('In_First_Set')) | |
groupMembersToInsert.add(new GroupMember(GroupId = groupId, UserOrGroupId = groupMemberPublicGroup)); | |
} | |
if (comparedSet.containsKey('In_Second_Set')) { | |
for (Id groupMemberPublicGroupId: comparedSet.get('In_Second_Set')) | |
groupMembersToDelete.add(new GroupMember(id = memberDetailIdToGroupMemberId.get(groupMemberPublicGroupId))); | |
} | |
} else if (parentPublicGroupIdToAccountId.containsKey(groupId)) { | |
//primary user group of all parents | |
HierarchyNode targetedNode = nodes.get(parentPublicGroupIdToAccountId.get(groupId)); | |
Set<Id> parentPublicGroupsToBePresent = new Set<Id>(); | |
for (HierarchyNode parentNode : targetedNode.parents) | |
parentPublicGroupsToBePresent.add(parentNode.node.PublicGroupId__c); | |
Map<Id, Id> memberDetailIdToGroupMemberId = new Map<Id, Id>(); | |
for (GroupMember groupMember : groupIdToGroup.get(groupId).GroupMembers) | |
memberDetailIdToGroupMemberId.put(groupMember.UserOrGroupId, groupMember.Id); | |
Map<String, Set<Id>> comparedSet = compareSets(parentPublicGroupsToBePresent, memberDetailIdToGroupMemberId.keySet()); | |
if (comparedSet.containsKey('In_First_Set')) { | |
for (Id groupMemberPublicGroup: comparedSet.get('In_First_Set')) | |
groupMembersToInsert.add(new GroupMember( | |
GroupId = groupId, | |
UserOrGroupId = groupMemberPublicGroup)); | |
} | |
if (comparedSet.containsKey('In_Second_Set')) { | |
for (Id groupMemberPublicGroup: comparedSet.get('In_Second_Set')) | |
groupMembersToDelete.add(new GroupMember(Id = memberDetailIdToGroupMemberId.get(groupMemberPublicGroup))); | |
} | |
} else if (primaryPublicGroupIdToAccountId.containsKey(groupId)) { | |
HierarchyNode targetedNode = nodes.get(primaryPublicGroupIdToAccountId.get(groupId)); | |
Set<Id> roleGroupsToBePresent = new Set<Id>(); | |
if (accountIdToPrimaryRoleGroupId.containsKey(targetedNode.node.Id)) { | |
roleGroupsToBePresent.add(accountIdToPrimaryRoleGroupId.get(targetedNode.node.Id)); | |
} | |
Map<Id, Id> memberDetailIdToGroupMemberId = new Map<Id, Id>(); | |
for (GroupMember groupMember : groupIdToGroup.get(groupId).GroupMembers) { | |
memberDetailIdToGroupMemberId.put(groupMember.UserOrGroupId, groupMember.Id); | |
} | |
Map<String, Set<Id>> comparedSet = compareSets(roleGroupsToBePresent, memberDetailIdToGroupMemberId.keySet()); | |
if (comparedSet.containsKey('In_First_Set')) { | |
for (Id groupMemberPublicGroup: comparedSet.get('In_First_Set')) { | |
groupMembersToInsert.add(new GroupMember(GroupId = groupId, UserOrGroupId = groupMemberPublicGroup)); | |
} | |
} | |
if (comparedSet.containsKey('In_Second_Set')) { | |
for (Id groupMemberPublicGroup: comparedSet.get('In_Second_Set')) { | |
groupMembersToDelete.add(new GroupMember(Id = memberDetailIdToGroupMemberId.get(groupMemberPublicGroup))); | |
} | |
} | |
} | |
} | |
delete groupMembersToDelete; | |
insert groupMembersToInsert; | |
} | |
//Wrapper Class that is used as nodes in the account hierarchy tree built | |
public class HierarchyNode { | |
public HierarchyNode parent; | |
public Account node; | |
public List<HierarchyNode> children; | |
public List<HierarchyNode> parents; | |
HierarchyNode(Account acc, HierarchyNode parent) { | |
this.parent = parent; | |
this.node = acc; | |
this.children = new List<HierarchyNode>(); | |
this.parents = new List<HierarchyNode>(); | |
this.parents.addAll(parent.parents); | |
this.parents.add(parent); | |
} | |
HierarchyNode(Account acc) { | |
this.parent = null; | |
this.node = acc; | |
this.children = new List<HierarchyNode>(); | |
this.parents = new List<HierarchyNode>(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment