1

I'm trying to keep the Account Team defined on a user (UserAccountTeamMember) in-sync to all the account this user owns (AccountTeamMember).

It starts usually in-sync when a user creates a new account. However it can be manually changed or diverge due to later changes of the Team on the user-record. I have already time triggers in place, which update all Accounts once per day.

There are also options in the UI to update the Account Team on accounts this user get transferred, but I found that this does not work reliable if you transfer account ownerships by APEX.

So I want to enforce that AccountTeamMember[] on each account in-sync to UserAccountTeamMember[] including the access levels. Without the access levels, I have it already working. But it is not possible to define the access level when you insert AccountTeamMember, because the field AccountAccessLevel is not writable. Looking around, I found that it can only be set on AccountShare, but if I'm adding AccountShares, the Reason (RowCause) ends up wrong - it gets only "Manual" but it has to be "Team"

I post my code below. But I'm wondering if there might be an Salesforce standard function for this or if anyone here has done it already? Sure the logic is in salesforce, but possible not exposed - which would be extremely sad.

Now that's what I have so far (working except the Access-Level flaw). I'm keeping a few external helper functions in the code. They should be self-explainatory and are improving readability of the code. Let me know in case it's a problem.

public static Map<Id,UserAccountTeamMember[]> getDefaultAccountTeam() {
    Map<Id,User>                            us                          = new Map<Id,User>( [ select Id, UserName from user ] );
    Map<Id,UserAccountTeamMember[]>         defaultMembersByOwnerIds    = new Map<Id,UserAccountTeamMember[]>(); 
    Map<String,UserAccountTeamMember[]>     defaultMembersByOwnerNames  = new Map<String,UserAccountTeamMember[]>(); 
    UserAccountTeamMember[]                 uatms                       = (UserAccountTeamMember[])xs.query(''
        +'SELECT *, User.UserName FROM UserAccountTeamMember '
    );
    for(User u : us.values()) {
        UserAccountTeamMember[]             usersTeamMembers            = new UserAccountTeamMember[]{};
        for(UserAccountTeamMember uatm : uatms) {
            if(uatm.OwnerId == u.Id) {
                usersTeamMembers.add( uatm );
            }
        }
        defaultMembersByOwnerIds.put(   u.Id,           usersTeamMembers );
        defaultMembersByOwnerNames.put( u.UserName,     usersTeamMembers );
    }
    return defaultMembersByOwnerIds;
}

public static void setAccountTeamToDefault(Account[] accs) {
    Map<Id,UserAccountTeamMember[]>         defaultMembersByOwnerIds    = getDefaultAccountTeam();              
    Id[]                                accIds  = xt.listIds( accs );
    AccountTeamMember[]                 atms    = new AccountTeamMember[]{};
    AccountShare[]                      ashs    = new AccountShare[]{};
    for(Account a : accs) {
        for(UserAccountTeamMember uatm : defaultMembersByOwnerIds.get( a.OwnerId )  ) {
            AccountTeamMember           atm     = new AccountTeamMember();
                atm.AccountId                   = a.Id; 
                atm.UserId                      = uatm.UserId; 
                atm.TeamMemberRole              = uatm.TeamMemberRole; 
            atms.add( atm );
        }
    }
    upsert atms;
}
1

As it turns out, I was already close to the solution. It works now with the code below, however I'm totally unhappy with such a verbose logic for a primitive thing like that.

So any simpler approach is still welcome.

May process is like that:

  • insert all the AccountTeamMember and accept the wrong AccountAccessLevel in the first loop

  • do not just create shares!

  • but select the implicitly generated shares from the AccountTeamMember insert and update them to finally end with the correct AccountAccessLevel

And here comes the code:

public static Map<Id,UserAccountTeamMember[]> getDefaultAccountTeam() {
    Map<Id,User>                        us                          = new Map<Id,User>( [ select Id, UserName from user ] );
    Map<Id,UserAccountTeamMember[]>     defaultMembersByOwnerIds    = new Map<Id,UserAccountTeamMember[]>(); 
    UserAccountTeamMember[]             uatms                       = (UserAccountTeamMember[])xs.query(''
        +'SELECT *, User.UserName FROM UserAccountTeamMember '
    );
    for(User u : us.values()) {
        UserAccountTeamMember[]         usersTeamMembers            = new UserAccountTeamMember[]{};
        for(UserAccountTeamMember uatm : uatms) {
            if(uatm.OwnerId == u.Id) {
                usersTeamMembers.add( uatm );
            }
        }
        defaultMembersByOwnerIds.put(   u.Id,           usersTeamMembers );
        defaultMembersByOwnerNames.put( u.UserName,     usersTeamMembers );
    }
    return defaultMembersByOwnerIds;
}

public static void setAccountTeamToDefault(Account[] accs) {
    Map<Id,UserAccountTeamMember[]>     defaultMembersByOwnerIds    = getDefaultAccountTeam();              
    Id[]                                accIds                      = xt.listIds( accs );
    AccountTeamMember[]                 atms                        = new AccountTeamMember[]{};
    AccountShare[]                      ashs                        = new AccountShare[]{};
    for(Account a : accs) {
        for(UserAccountTeamMember uatm : defaultMembersByOwnerIds.get( a.OwnerId )  ) {
            AccountTeamMember           atm                         = new AccountTeamMember();
                atm.AccountId                   = a.Id; 
                atm.UserId                      = uatm.UserId; 
                atm.TeamMemberRole              = uatm.TeamMemberRole; 
            atms.add( atm );
        }
    }
    upsert atms;
    accs = database.query(xs.soql(''
        +' SELECT Id, OwnerId, (SELECT Id, UserOrGroupId, AccountAccessLevel FROM Shares WHERE RowCause=\'Team\' ) '
        +' FROM Account WHERE Id IN : accIds ')
    );
    for(Account a : accs) {
        Map<Id,UserAccountTeamMember> uatmsByUserIds = new Map<Id,UserAccountTeamMember>(); 
        for(UserAccountTeamMember uatm : defaultMembersByOwnerIds.get( a.OwnerId ) ) {
            uatmsByUserIds.put( uatm.UserId, uatm );
        }
        for(AccountShare ash : a.Shares) {
            ash.AccountAccessLevel              = uatmsByUserIds.get( ash.UserOrGroupId ).AccountAccessLevel;
            ashs.add( ash );
        }
    }
    update ashs;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.