Skip to content

Instantly share code, notes, and snippets.

@Walletau
Last active April 1, 2017 17:23
Show Gist options
  • Save Walletau/c7db07d9e8c9e46f735a6332cdb94f78 to your computer and use it in GitHub Desktop.
Save Walletau/c7db07d9e8c9e46f735a6332cdb94f78 to your computer and use it in GitHub Desktop.
RH Snip3
///////////////
//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