User offboarding automation

When a user is deactivated, we want to notify their manager to review the records that the User owns, to determine which ones should be transferred and which ones can be left alone.

With Spring 15, most any user can edit a record owned by an inactive user so it makes sense to review and leave them alone unless someone is taking over the relationship / opportunity.

So, we pulled together a workflow rule that triggers an email to manager
that shows a count of records owned by user, and links to reports where they can view records.

The email uses a visualforce email template, with a custom component that calculates the number of records owned by the user, and includes a link to reports that are filtered by the UserID, so it shows the actual records owned by the user.

Note: reports must filter on 18 character ID - as that is what the component delivers, since its running in code.

I’m including the code as-is, below. There is some fun stuff in there where it selects for specific lead and opp record types, lead statuses, etc. But the basic gist should be reasonably easy to follow.

The workflow rule is straightforward. You just need a custom field to store the manager email, as for some reason manager is not an available “related user” option.

Also, I did not write this code. It was written by Jaisuresh Puratchiraj of Orbit Innovations for work contracted by Ashoka (my current employer). Ashoka has granted permission for this to be shared under creative-commons attribution license.

Code: VF component

<apex:component access="global" controller="UserDeactivation">

    <apex:attribute name="userID" description="User Id" type="String" required="required" assignTo="{!uId}" />

    <apex:attribute name="baseURL" description="URL of Instance" type="String" required="required" assignTo="{!base}" />    

    <apex:outputLink value="{!base}/00O40000003cFNi?pv0={!uId}">Contacts</apex:outputLink>: {!ContactCount} <br/>

    <apex:outputLink value="{!base}/00O40000003cFNT?pv0={!uId}">Organizations</apex:outputLink>: {!OrgCount} <br/>

    <apex:outputLink value="{!base}/00O400000042vqw?pv0={!uId}">Leads</apex:outputLink>: {!LeadCount} <br/>

    <apex:outputLink value="{!base}/00O400000043JvH?pv0={!uId}">Opportunities</apex:outputLink>: {!OppCount} <br/>

    <apex:outputLink value="{!base}/00O40000003dQ1m?pv0={!uId}">Campaigns</apex:outputLink>: {!CampCount}

</apex:component>

Code: Apex Class

public class UserDeactivation {

    public UserDeactivation(ApexPages.StandardController controller) {

    }

    public String base {get; set; }
    public String uId { get; set; }
    public Set<Id> setOppRecType = new Set<Id>();
    public Set<Id> setOppRecTypeClosed = new Set<Id>();
    public Set<Id> setLeadRecType = new Set<Id>();

    public String agContactCount {
        get {
            aggregateResult ag = [select count(id) from Contact where ownerId =: uId];
            String cCount = String.valueof(ag.get('expr0'));
            return cCount;
        }
        set;
    }
    public String getContactCount() {
        return agContactCount;
    }

    public String agOrgCount {
        get {
            aggregateResult ag = [select count(id) from Account where ownerId =: uId];
            String cCount = String.valueof(ag.get('expr0'));
            return cCount;
        }
        set;
    }
    public String getOrgCount() {
        return agOrgCount;
    }

    public String agCampCount {
        get {
            aggregateResult ag = [select count(id) from Campaign where ownerId =: uId ];
            String cCount = String.valueof(ag.get('expr0'));
            return cCount;
        }
        set;
    }
    public String getCampCount() {
        return agCampCount;
    }

    public String agOppCount {
        get {
            aggregateResult ag = [select count(id) from Opportunity where ownerId =: uId AND (RecordTypeId in: setOppRecType OR IsClosed = False)];
            String cCount = String.valueof(ag.get('expr0'));
            return cCount;
        }
        set;
    }
    public String getOppCount() {
        return agOppCount;
    }

    public String agLeadCount {
        get {
            aggregateResult ag = [select count(id) from Lead where IsConverted = False AND ownerId =: uId AND RecordTypeId in:setLeadRecType AND (Status != '1st Opinion - Rejected & Archived' AND Status != 'Rejected')];
            String cCount = String.valueof(ag.get('expr0'));
            return cCount;
        }
        set;
    }
    public String getLeadCount() {
        return agLeadCount;
    }

    public String urlString { 
        get {
            urlString = URL.getSalesforceBaseUrl().toExternalForm() + '/setup/user/userstorageusage.jsp?id=' + uId;
            return urlString;
        }
        set; 
    }

    public String getURLStr() {
        return urlString;
    }

    public UserDeactivation() {
        list <RecordType> lstOppRecType = [select id, Name from RecordType where sObjectType = 'Opportunity'];
        list <RecordType> lstLeadRecType = [select id, Name from RecordType where sObjectType = 'Lead' AND (Name = 'Venture Nominee' OR Name ='Venture Nominee Convert' OR Name = 'Ashoka Candidate')];

        setLeadRecType = (new Map<Id, RecordType>(lstLeadRecType )).keySet();
        for (RecordType rtRow: lstOppRecType) {
            if (rtRow.Name == 'Fellowship' || rtRow.Name == 'ASN') {
                setOppRecType.add(rtRow.id);
            } else if (rtRow.Name == 'Donation' || rtRow.Name == 'Grant' || rtRow.Name == 'In Kind Donation' || rtRow.Name == 'Pledge' || rtRow.Name == 'Simple Gift' || rtRow.Name == 'Venture Selection') {
                setOppRecTypeClosed.add(rtRow.id);
            }
        }
    }
}

 
4
Kudos
 
4
Kudos

Now read this

Quirks with case and lookups in field references in visual workflow

I’ve been running into a number of bizarre issues with field references in flows. To illustrate these, I created a simple flow with a fast lookup to contact to an sobject variable named “sovContact” and a screen to display account... Continue →