Extracting Files from Salesforce
It’s super simple to add files to Salesforce. Just drag and drop. Easy as pie. But if you need to get those files out of Salesforce, it can be a challenge. As an admin or developer, there isn’t an interface that allows you to simply select the Files and download them.
Recently, I had to produce files related to a specific custom object. I tried several different options to get to the Files I needed. I tried the Data Export option, but that didn’t allow filtering. I tried going through Premier Support Admin Services, but it’s not option. I was referred to AppExchange apps, but they were all outdated or came with a price tag. I tried Data Loader, too, but no luck. Then, I ran across a comment from Johan Karlsteen on the developer forum saying that he had built a python script to make this work. (His blog on this topic.) He also shared the code on github. His solution was exactly what I needed.
To meet my specific use case, I made a few changes to the code. To reduce API calls, I added some batching capabilities. To help with mapping the files to their related records I added a file mapping csv export. And I added some logic to remove strings from the file name that would break the file writing process.
If you’re struggling with the same scenario, I highly recommend this method. It can save a lot of time and effort!
Merge Opportunities with Flow
I’ve been eagerly anticipating the new Lightning Flow Builder for months. So, I was giddy, in a very geeky way, to finally have a reason to build a new Flow after the Spring 19 release.
I’ve been eagerly anticipating the new Lightning Flow Builder for months. So, I was giddy, in a very geeky way, to finally have a reason to build a new Flow after the Spring 19 release.
The chance finally came when discussing the need to merge opportunities. Specifically, to merge products from two opportunities together into a single opportunity. There are apps on the app exchange that do this, but I really wanted to use Flow. I began by outlining the steps that should be taken to walk users through the process. Then, added in some details until I had a good ideas of all of the scenarios that were allowed and not allowed. Some of the things that had to be considered were:
Currency: The Opportunities needed to be in the same currency.
Price Book: The Products all needed to be listed in the same Price Books.
Record Type: Business rules that prevent certain types of Opportunities from being merged.
Duplicate Products: Don’t produce duplicate Opportunity Products during the merge.
The whole flow was pretty large, but the new designer made it manageable to navigate and reorder as needed. Here is a snapshot of the Flow.
I followed the guidelines for displaying flow stages with a Lightning Component to the Flow to give users a sense of progress through the wizard, added SLDS classes within text templates helped to spruce up some of the screens, and used the sweet Lookup Component from Alex Edelstein.
Here’s an example of the flow on a couple of test Opportunities. (Yes, I like to use Pearl Jam as my test account. Don’t hate. I graduated high school in 99’.) In this scenario we have a Renewal Opportunity for a one year subscription to a product. The same Account is also interested in a new product. They would like to co-term the two subscriptions. This can messy when there are several products. So, this wizard walks the user through the following stages to make it clean and simple. The flow is launched from a flow action on the Renewal Opportunity (Master).
Search: Find an Opportunity to merge with the Master Opportunity.
Verify: Make sure that the user has the selected the correct Opportunity
Validate: Runs the checks mentioned above to ensure these Opportunities can be merged
Confirm: Give the user a chance to commit and provide a reason for the merge.
Complete: End with a success message.
Bulk Reassign Opportunities from List View
A simple 3 step declarative solution to bulk reassigning Opportunities.
Recently, my team and I developed a declarative method to reassign Opportunities from a list view. Salesforce already had this capability for Cases, and we mistakenly assumed that the functionality existed for Opportunities. However, that functionality still hasn't been added as of Summer 18'. This is a simple solution that will hopefully save others a ton of time in maintaining clean assignments. It is a bit of a hack, but it works!
Opportunity owner is locked for editing within a list view. However, the owner can be updated with Process Builder. So, the workaround is to add another User based field that can be edited from the list view and allow Process Builder to perform the update in the background. Here is the summary, then screenshots.
Summary
- Create "New Owner" lookup field
- Update Owner to the New Owner value with Process Builder
- Add the New Owner field to any Opportunity list view that supports Inline Edit
Screenshots
1. Create "New Owner" lookup field
Add a new lookup field to the Opportunity. The field should lookup to the standard User object.
Limit field level security accordingly and place the field on a page layout so it is available for use in a list view.
2. Update Owner to the New Owner value with Process Builder
Create a Process Builder flow that sets Owner = New Owner when New Owner is not null. Always clear the New Owner so it can properly trigger this change in the future.
3. Edit from any List View
Now, you can add New Owner to any list view (within a single record type) and perform a reassignment in bulk.
Flow Logging
Add logging steps to your flow to capture usage statistics, produce debug logs, or audit user actions.
Flows can be powerful and make your users more productive, but with great power... you know the rest. Sometimes we need to know who is running the flows we build, how often the flows are being run, which options/paths are selected, and what the data looks like while the flow is running for audit or debug purposes. Tracking these things can be simple by setting up a Flow Log object and utilizing a reusable sub-flow within your flows as a logging step. Together the Flow Log object and the sub-flow enable Debugging, Auditing, and Usage Statistics.
Setup
Setup is super simple to enable this functionality. Just create a new object named Flow Log(s) and add as many custom fields as needed. I recommend auto-number for the Name field. In this example I created fields for the Flow Name, Flow Step, and Debug Message. I can capture user information just by utilizing the Created By field. Created Date gives me a time stamp also.
I prefer utilizing a sub-flow for logging because it feels like a built in tool in the palette.
Usage Statistics
Adding a logging step to each of flows can allow you to determine which flows are being used the most/least. Knowing which flows are used the most/least can be very helpful in determining the impact of a change. Usage stats can also be helpful in determining adoption. Is everyone aware of that awesome new flow you built? Are they using it? With usage stats you can answer those questions and determine if additional training/promotion is necessary.
Here is an example of a flow that has each path logged so I can determine how many times the flow has been run and which paths were taken:
Debugging
If a flow fails, admins receive a very detailed email explaining every step of the flow. But, if you are trying to diagnose the behavior of a flow that is not failing it can very hard to peek inside. By adding logging checkpoints within your flow you can inspect variable values or options that were selected.
Audit
Similar to debug logs, adding an auditing step to a flow can make it simple to answer questions about who executed certain tasks. Some of the tasks that a flow performs could be sensitive or restricted in some way. By adding an auditing step you add the ability to report on user behavior.
Account Notification and Filtered Related List with Conditional Visibility
How can we make it obvious to anyone viewing an Account that the Account has upcoming renewals?
Facing some well known platform limitations we utilized a collection of declarative to solve the problem. By combining these declarative steps we were able to build a solution to our problem without code in less than an hour.
The Story
Yesterday, my team and I were presented with a challenge:
How can we make it obvious to anyone viewing an Account that the Account has upcoming renewals?
We knew we wanted to use Lightning's Component Visibility feature to show a new section on the Account page that contained a notification and a list of the renewals. It sounds like a simple problem, but it revealed a current limitation of the platform. There isn't a standard component (Related List or List View) available that supports additional dynamic filtering. Because we store renewals as a Type of Opportunity I assumed that I was going to need to build my own Lightning Component to solve this one... until I came across this brilliant post by Doug Ayers called Filter Related Lists without Code.
The solution presented in Doug's article gave us a perfect way to get a filtered Related List by populating a new lookup field on the Opportunity. But, how could we update all existing Opportunities that meet our criteria, flag all future Opportunities, and remove Closed Opportunities?
To overcome that hurdle we utilized another of Doug Ayers' ideas! We used Mass Action Scheduler to grab all of the records that met our criteria and pass them to a Process Builder flow to populate our new lookup field. We scheduled the job to run daily and we added another Process Builder flow to remove the value from the lookup field when the Opportunity was Closed. This combination keeps the data in our new Related List accurate.
The last step was to only show our notification and new Related List when the list contains records. For this we turned to one of our most heavily utilized tools Declarative Lookup Rollup Summaries by Andrew Fawcett. This tool allowed us to store a count of Opportunities that had a value in our new lookup field. We used this count in Component Visibility to dynamically show our new Related List of upcoming renewal Opportunities.
By combining all of these declarative steps we were able to build a solution to our problem without code in less than an hour. For bonus points we wrote a tiny lightning component to make the notification look nicer with the lightning:card component and the action:priority icon.
The Steps
Here is an overview of the steps:
- Add a new lookup field on the Opportunity named Upcoming Renewals that looks up Account (do not put on page layout)
- Add a number field on the Account to hold named Upcoming Renewals Count to act as a roll-up summary via DLRS
- Create a list view or report to produce a list of Opportunities with IDs
- Add a new Invocable Process Builder flow to set Upcoming Renewals equal to Account.Id
- Add a standard Process Builder flow to remove the Upcoming Renewals lookup value when the Opportunity is Closed
- Schedule a Mass Action Scheduler job to call your Invocable Process Builder flow for each record in your list view/report
- Create a real-time DLRS summary trigger to produce a roll-up summary count of Upcoming Renewals
- Utilize component visibility in Lightning App Builder to only show the notification and Upcoming Renewals related list when Upcoming Renewals Count is greater than zero
- (Optional) Create a Lightning Component to make your notification look nice
Here are the detailed steps with screenshots:
Data Model
- New Lookup Field named Upcoming Renewals on Opportunity
- New Number Field on Account named Upcoming Renewals Count
List View
- New List View on Opportunity named Upcoming Renewals - 90 Days
Process Builder
- Add an Invocable Process Builder Flow that populates the Upcoming Renewals lookup field with the Account Id
- Add a standard Process Builder Flow that removes the Upcoming Renewals lookup field value when the Opportunity closes (this keeps the Related List clean as Opps get closed)
Declarative Lookup Rollup Summaries (DLRS)
- Create a new realtime summary on Account that is a count of Opportunities that are related via the Upcoming_Renewals__c look field
Mass Action Scheduler
- Utilize the List View Upcoming Renewals - 90 Days to get our list of records
- Invoke the Process Builder Opportunity - Set Upcoming Renewals
- Schedule accordingly - we will run daily
Lightning App Builder
- Add a Related List - Single component (be sure to add to Page Layout first) that references our new Upcoming Renewals related list
- Add a Rich Text field to help draw attention to the section of the page
- Set Component Visibility based on Upcoming Renewals Count > 0
(Optionally) You can create a simple Lightning Component to make your notification look nice.
After putting all of these pieces together, the Account page will now draw attention to the fact that the Account has upcoming renewals and display a full list of renewal Opportunities with a close date in the next 90 days. As these Opportunities are closed they will be removed from the list and the section will no longer show on the page.
Experiments with Dynamic Flow Component
Here are three concepts that I'm experimenting with as use cases for DFC:
- Prompt for required field when viewing record (without editing)
- Intelligent Sales Guide to provide suggestions or recommend flows
- Prompt users to create a Case based on a calculated value
Recently, I've been experimenting with a new project called the Dynamic Flow Component (DFC) by Andrew Fawcett (AndyInTheCloud).
Here are three concepts that I'm experimenting with as use cases for DFC:
- Prompt for required field when viewing record (without editing)
- Intelligent Sales Guide to provide suggestions or recommend flows
- Prompt users to create a Case based on a calculated value
DFC was interesting for these scenarios because it could:
- Run initialization logic to route to the appropriate Flow
- Automatically open a Flow
- Provide a consistent experience across objects (always in the same location)
- Access current/changing record data through the use of Lighting Data Service
Prompt for required field when viewing record (without editing)
Recently, my team and I were asked to make Industry required on the Account object in an org with about 20,000 existing Accounts. A back-fill on 20,000 records is no big deal, but in this case we were collecting the data for the first time and the information was simply unknown to us without research. After making the field required we quickly saw automated processes and unit tests begin to fail. Instead of making it required at the data level, we made the field required only through page layouts. Making the field required on page layout allowed automated processes and unit tests to continue to function without throwing errors, but users would not be required to populate the field unless they edited the record. By implementing DFC we can prompt users to update the required field as soon as they view the record page.
flow controller
I have it helpful to use one flow per object as a controller for routing to other flows as needed. In this case, in my Account Controller Flow I check to see if Industry is Null or equal to "Undetermined" and route to my Account Industry Flow. If not, I route to a default flow for the object that contains a screen letting the user know everything is in good shape on this record.
prompt user for value
Within the Account Industry Flow I pass in the flowtb_record and display a screen prompting the user to select a valid value. When the user selects a value the record is updated and the screen is refreshed. This causes the Flow Controller to rerun and could route to a different flow if needed. This is a simply pattern that can be applied to lots of Data Completion scenarios.
Intelligent Sales Guide
Our team has also been playing with the idea of making recommendations through a Guided Sales tool similar to a Sales Playbook and to provide access to several "helper" flows without creating several buttons or additions to the page layout. This concept is bit more complex and requires considerable planning. Here are some of the ideas we have compiled so far:
- Suggested actions by Stage
- Field completion by Stage
- Follow up reminders
- Close Date extension
- Changing the currency of an Opportunity (and products)
- Adding primary contact
- Adding competitor information
Prompt users to create a Case based on calculated values
We track equipment status in Salesforce and log the last time a "unit" has called home. We can track the duration since it last called and prompt a user to create a case if it has been down too long.
The real advantage here is that DFC can check the current value of the formula field and determine if action is needed or not. Another interesting concept for this use case is to utilize a project by Doug Ayers called Mass Action Scheduler that could run a report of all units that have exceeded a given time threshold and automatically create cases for them.