Posts

Update Knowledge Articles in Bulk

Image
Recently we had a big Knowledge Centric Support (KCS) initiative where we generated a ton of Articles for use in a Community. (We're still on Classic Knowledge.)

Problem is, some users forgot to tick the "Customer" box when creating the Articles. So those articles didn't appear to external users in the Community.


You can update these Articles in bulk, but you need to use a few obscure hooks in Apex. This method will create a draft of the Article, update the Knowledge Article Version, and then re-publish without creating a new Version.

The following code will update the 'IsVisibleInCsp' flag for a single Article specified in the 1st query, which will make it visible to Customers.

Here's a bulkified version. This is heavy on the CPU so I run it 10 at a time.

When going over these in bulk, you might run into a situation where there is an existing draft of an article that has been previously published; i.e., it's actively being updated. In this example, …

Custom Lookup For Flows to Avoid "Disjunctions Not Supported"

Image
Because custom metadata and Flow don't mix, I had to create a service that would run the custom metadata lookup in Apex, where I can control the bulkification. Code
Here is some code that will achieve this. It takes a list of field names and a list of values, and a table name, and returns the value from the lookup. To install the code, open Developer Console, and create four files: FlowLookupFlowLookupRequestFlowLookupResultMyExceptionYou can copy/paste the code from Github into those files, then save them. That will make the plugin available to your Flow.
Step-By-Step Usage
Here's an example that looks up a value called a "fireball" from a custom metadata table and assigns the value to a record called iLead__c.

Request and Response Formats
The process has a request and a response. The request contains:
Query Fields - a list of the fields you want to queryQuery Values - another list of the values for the above fieldsResult Field - the field to pull the result fromTable Name …

"Disjunctions not supported" - Why Custom Metadata and Flow Don't Mix

Salesforce has been focusing a lot on Flow recently, as they should. It splits the difference nicely between Process Builder and Apex code.
We recently used Flow to implement what I'd expect is a common use case - when a record is created, lookup a value from a table and update the record. In this case, it's a light lead score we call a "fireball" value.
This worked great since in most use cases we'd get one record at a time. But we found during Lead conversion, we would get a few records through at a time, which caused the process to break with a really odd error: Error Occurred: This error occurred when the flow tried to look up records: Disjunctions not supported. After some research it became clear that this is the error you get when you try to query a custom metadata table using an "OR" condition. But my Flow didn't use an "OR" condition in the metadata lookup.
The answer was lurking in this obscure documentation: When you define multiple f…

A Pattern for Apex Test Code So You Can Forget About Required Fields

Yeah, yeah, yeah, just take me to the code.
I recently had the opportunity to start writing some code in a brand new org, which got me thinking about the best way to do test object creation. You know, that annoying problem where you need to generate an Account in a test class about 77 times. Here’s a pattern I came up with.

This method involves some overhead but it has the advantages of (1) allowing you to set defaults for certain objects so you don’t have to worry about them – for some objects create them with all defaults with just one line, and (2) a generic, repeatable pattern.

It’s based on an abstract class that implements the base operations using some generic sObject magic outlined here.

A lot of code in this post, bear with me.

(That's a basic version, for something more robust, look here.)
For each object you will use, you need to create a class that implements the abstract factory class.
Then, in your test code you would need to instantiate the factory for eac…

Salesforce: A Practical Approach to Queueables

Image
Update, June 2020: Like to live dangerously? Go straight to the code. I've set up a project with the framework and some examples.
Salesforce triggers are great, but they run synchronously by default. What if you want to speed up the user experience and run noncritical tasks in the background? That’s what Queueable is for. But it’s not as simple as it’s made out to be.I think most organizations have a simple process where they have a Trigger that calls a Trigger Handler. With a Queueable, you might think you can do something like this.Trigger:Trigger Handler:Then a Queueable to implement your business logic. 

The problem with this approach is, as Brian Fear (aka sfdcfox) said in his outstanding response to my StackExchange Question: “The rule is that if you’re synchronous, you get 50 jobs for that transaction. Once you go asynchronous, you get only one child allowed.”Brian went on to provide an example, which works great. Basically it detects if you’ve “Gone Synchronous” and runs th…

Salesforce: Check if Record Has Been Manually Edited

We recently had a requirement in Salesforce that was a little unique. An ongoing automated process would update the associated Contact to a record, however they didn’t want the automated process to do the update if the field had been updated by a human. Makes sense – if someone takes the time to make a manual association of a Contact to a record, then it’s probably better information than the automatic matching algorithm.As far as I can tell it’s impossible at runtime to know if the edit is due to a UI edit or is coming from code, so that’s out.Here’s how we made it happen. The idea is to have a “last updated by code” checkbox that will be set by a workflow. But in order for it to know if it’s been updated by code, you need a 2nd checkbox that is only updated in Apex.First, make two checkboxes on your record:
Contact_Change_Trailing_Lock__c
Contact_Last_Changed_By_Code__cSet the latter to true by default when a new record is created.When your code updates the record, set Contact_Change_…

MavensMate: TLS 1.0 Deprecation Error (UNSUPPORTED_CLIENT)

Image
If you use MavensMate for SublimeText (on Mac) for your Salesforce development, you might have encountered an issue after your org was updated to Summer ’16. Apparently Salesforce deprecated TLS 1.0 and MavensMate doesn’t support it in versions less than 7.0.There is a lot of information out there but it’s all over the place. Also the MavensMate community has a maddening tendency to assume everyone’s an uber-developer and understands all the shortcuts and terminology.Here’s how to nix the problem.Download and install the MavensMate.app from GitHub.In Sublime Text, edit your Package Control settings for your user. You can’t edit the global ones.
Add the following line to your user settings.[code lang=”javascript”]
"install_prereleases":
[
"MavensMate"
],[/code]Mine looked like this when I was done.
Quit and restart Sublime Text.In Sublime, use COMMAND+SHIFT+P and type “Package Control”. Run “Upgrade Package”.Now, in the MavensMate app you installed, you need to Settings i…