REVISED: Update Inactive User to Active User as Contact Owner : jenwlee

REVISED: Update Inactive User to Active User as Contact Owner
by: jenwlee
blow post content copied from  Jenwlee's Salesforce Blog
click here to view original post


Note: This blog post was originally created in 2018 and has been updated to reference Flow Builder.

Handoff

This blog post was inspired by Trailblazer community member, KC Brotherton.

Special S/O to Jason Teller, Salesforce Process Automation Product Management for the assist on the workaround.

TBCommunityPost.GIF

Many times, people leave a company and you need to update the record ownership to an active internal user. This process can be automated using Salesforce flow by creating a process that invokes a flow.

Easy peasy, right? Not quite. If the flow is invoked from an immediate action in process builder, when the process executes, it will result in a flow error: “The flow tried to update these records: null. This error occurred: MIXED_DML_OPERATION: DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa): Contact, original object: User.”

In Summer ’18, more granular batching of scheduled process actions and waiting flow interviews was introduced to avoid runtime errors when running DML operations on both standard and setup objects. However, the flow runtime errors continue to occur when running DML operations on both standard and setup objects in the same batch transaction. To work around this, we will use a scheduled action to invoke the flow.

Note: If you are wondering if you can do this all in a record triggered flow. The answer is no. You will get a flow error when you try to run the flow. Until there is a way in the record-triggered flow to break the transaction to eliminate the mixed DML operation, you will not be able to get away with configuring this in a record triggered after save flow.

FLOW_ELEMENT_ERROR| The flow tried to update these records: null. This error occurred: MIXED_DML_OPERATION: DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa): Contact, original object: User.

Here are a few lessons learned from implementing this use case:

  • Learn how to invoke flow from a process.
  • Avoid having to hardcode IDs in our flows. In this example, we use a custom label. There are alternatives to this design, such as using custom metadata type or performing a record lookup of the user object in the flow to obtain the ID based on the user’s name. (Note: Hardcoded Ids are bad practice.)
  • Do not perform database commits within a loop.
  • Provide descriptions, where provided, in Salesforce. This may be tedious step, I know, but your future self will thank you when you are trying to remember what you configured or assist other/future admins when troubleshooting or enhancing what was built. This includes variables, the purpose of a flow, what each flow element does, etc.

Business Use Case:  Addison Dogster is the system administrator at Universal Containers. Mary Markle is the Director of Operations. She mentioned to Addison that there are contacts in the system owner by people who are no longer with the company. She would like these contacts assigned to designated “generic” user until the contacts are assigned out to actual users. Mary would like to automate the process of assigning the contacts to the generic user account.

The process Mary would like to automate is as follows:

ProcessWalkthrough.GIF

View image full screen

Solution: Being the #AwesomeAdmin that Addison is, she was able to solution this declaratively using Salesforce Flow. She builds the first part of the process using Process Builder run on the User Object and the latter part of the process in Flow Builder (noted as Cloud Flow Designer in the illustration below) by creating a flow. Note: Fast Lookup is now Get Records and Fast Update is now Update Records in Flow Builder.

ProcessWalkthrough-Solution.GIF

View image full screen

The outcome looks like this:

Process created in Process Builder on the User object that runs when the active field is changed and the active field is false. Then, 0 hours after the Last Modified Date, invoke the flow created in Cloud Flow Designer.

ProcessBuilder-UpdateUser.GIF

This flow does the following: (1) looks up all contact records where the contact owner is the inactive user, (2) determine if there are records in the collection, (3) if there is a collection, then take each record and do the following: (3a) assign the new user as the contact owner and (3b) add the contact record to the collection to update and finally, outside the loop, update all contact records in the collection.

Note: The update action is performed OUTSIDE the loop, not inside it. Similar to apex, when DML statements (insert, update, delete, undelete) are placed inside a for loop, database operations are invoked once per iteration of the loop making it very easy to reach these governor limits. Instead, move any database operations outside of for loop. The same applies to flow (remember, Salesforce translates flow into code behind the scenes).

UpdateUserFlow

View image full screen

Quick Steps:

1. We are going to create a custom label to hold the Salesforce Id of the user who will be assigned to the contacts when a user is deactivated*. In Classic, Custom Labels is found under Create | Custom Labels. In Lightning, you can find it under User Interface | Custom Labels.

As mentioned above, there are multiple ways to not hardcode Ids in flow. Custom label is just one of the ways. Custom metadata types, performing a record lookup in flow will also do the trick. We just don’t want to hardcode the Id in flow so we can change the Id without having to make a new version of the flow.

CustomLabel-UserId.GIF

2. Let’s create the flow. For those using Salesforce Classic, flow can be found in Create | Workflows & Approvals | Flows. In Lightning Experience, it is found under Process Automation | Flows.

A. Let’s create our flow resources.

Best practice tip: Provide a description so you and other/future admins know what this flow resource is used for.

Create a variable varUserId to store the inactive user’s Id that will be passed from process builder as an input into flow.

UpdateOwnerFlow-varUserId.GIF

This sObject Collection Variable will hold all the contact records that will be updated to reflect the new contact owner.

UpdateOwnerFlow-sCollectionUpdateContacts.GIF

Lastly, we will create a formula resource to call the UserId custom label into the flow.

UpdateOwnerFlow-Formula.GIF

B. First, we need to perform a lookup to pull all the contacts associated with the deactivated user. We are using the Get Records resource because we are pulling a collection of Salesforce records. We are looking up the Contact object where the OwnerId equals the deactivated userId. Once found, we will store the records and store the Id and the OwnerId.

Best practice tip: Provide a description so you and other/future admins know what this flow element is used for.

UpdateUserFlow-GetRecordsView image full screen

C. Next, we will a Decision flow element to determine whether the fast lookup in the previous step yielded in any contacts. The “Found” outcome looks at the items in the {!Lookup_contacts_owned_by_inactive_user} (collection from the Get Records) is null false. Two negatives equal a positive, which means the collection has at least one or more contact records.

Best practice tip: Provide a description so you and other/future admins know what this flow element is used for.

UpdateUserFlow-DecisionView image full screen

D. We now need to create a Loop flow element so that we can go through each contact record in the collection. It looks at the sObject Collection Variable from the Get Records {!Lookup_contacts_owned_by_inactive_user} and put each contact record into a loop variable {!Loop_de_loop}.

UpdateUserFlow-Loop

E. For each loop record, in the Assignment flow element, we will assign the new user as the contact owner. Variable is {!Loop_de_loop.OwnerId} (i.e. loop record’s ownerId field) equals {!NewUser}.

Best practice tip: Provide a description so you and other/future admins know what this flow is used for.

UpdateUserFlow-Assignment

F. For each loop record, in the Assignment flow element, we will add the loop contact record to a new collection that will be updated. {!sCollectionUpdateContact} add {!Loop_de_loop}

Best practice tip: Provide a description so you and other/future admins know what this flow is used for.

UpdateUserFlow-Assignment1

G. Now, we need to create the Update Records flow element to update all the contacts in the sObject Collection Variable {!sCollectionUpdateContact}.

Best practice tip: Provide a description so you and other/future admins know what this flow is used for.

UpdateUserFlow-UpdateRecords

H. Set your flow starting point. And connect the flow elements, outcome connector and loop connector to match the below…

UpdateUserFlow-Connectors

I. Save/Save As and provide the following properties.

Best practice tip: Provide a description so you and other/future admins know what this flow is used for.

UpdateOwnerFlow-Properties.GIF

J. Click the “Activate” button.

3. Now, create a new process using process builder. In setup, go to Create | Workflows & Approvals | Process Builder in Salesforce Classic or Process Automation | Process Builder in Lightning Experience.

A. Click on the New button to create our new process. Complete the information below and select “A record changes.”

Best practice tip: Provide a description so you and other/future admins know what this process is used for.

ProcessBuilder-NewProcess.GIF

B. Specify User as the object, when a record is created or edited.

ProcessBuilder-UpdateUser-UserObject.GIF

C. Specify the Criteria Node. This needs to evaluate to true for it to execute. We will call the criteria “Inactive.” In this situation, we are going to use the formula as we cannot specify the IsChanged condition with the Conditions are met specification. The criteria is if the user’s active field is changed AND the user’s active field is false (unchecked).

We have to check the box to Yes under Advanced “Do you want to execute the actions only when specified changes are made to the record.” If this is not checked, you will not see the Scheduled Actions.

ISCHANGED([User].IsActive) &&
[User].IsActive = false

ProcessBuilder-UpdateUser-CriteriaNode.GIF

D. To avoid the mixed DML action on standard and setup objects that would result if you invoke the flow from an immediate action, we will configure a scheduled action to take place “0 hours after the LastModifiedDate.”

ProcessBuilder-UpdateUser-ScheduledAction.GIF

Select Flow as the action, select the flow created in Step 2. Specific the flow variable varUserId and pass in the field reference [User].Id onto the flow.

ProcessBuilder-UpdateUser-InvokeFLow.GIF

E.  Click on the Activate button to activate the process builder.

Now, before you deploy the changes to Production, don’t forget to test your configuration changes.

  1. Make a user the contact owner for several contact records.
  2. Deactivate the user.
  3. Verify that all the contacts owned by the deactivated user have been updated to the new user.

Deployment Notes/Tips:

  • The process builder, flow and the custom label can be deployed to Production in a change set (or can be deployed using a tool such as Metazoa’s Snapshot).
  • You will find the process builder and flow in a change set under the Flow Definition component type.
  • Activate the process builders and flow post deployment as they deploy inactive in Production, unless with Winter ’19, you have opted in on the Process Automation Settings screen, to “Deploy processes and flows as active.” NOTE: With this change, in order to successfully deploy a process or flow, your org’s Apex tests must launch at least 75% of the total number of active processes and active autolaunched flows in your org.

January 05, 2021 at 06:30PM
Click here for more details...

=============================
The original post is available in Jenwlee's Salesforce Blog by jenwlee
this post has been published as it is through automation. Automation script brings all the top bloggers post under a single umbrella.
The purpose of this blog, Follow the top Salesforce bloggers and collect all blogs in a single place through automation.
============================