Traversing the declarative and programmatic divide: The same task with 3 different Salesforce Tools
Trailhead is a training oasis for administrators and developers alike. Okay, it’s more than just a learning oasis, it’s a community, a support network, and…it’s free! However, there aren’t many trails for “Admin/Developers” or “Developer/Admins” — a trail for when you have a few hours to do something and you need to try out different solutions: declarative, code-based, or hybrid, so I’m hoping to help fill that gap.
So, let’s start with something simple, here’s our business case:
The client wants 2-business days added to a custom field called “Shipping Date” on the Case object when the Case Status changes to “Approved”.
What this tutorial covers, the same task using 3 different Salesforce tools:
· Declarative approach: Using Workflow Rules
· Hybrid approach: Using Process Builder & Calling An Invocable Apex Method
· Code-based approach: Using a Trigger
Setup: Add custom field to the Case object with the following criteria, reference the gif below if you are unsure of how to do this.
Field Label: Shipping Date
Field Name: Shipping_Date
Description: Field to store the shipping date.
Visibility: All profiles
Page Layouts: Select all available
Setup: Customize the “Business Hours”.
No one really wants to work weekends, right? Why are we messing with Business Hours? Because this is a great resource that we’ll tap into later when we’re looking at hybrid and code-based solutions. Business Hours lets us simplify by providing a template where we can add in holidays, extended hours for different workdays, etc. If you try to do that either purely declaratively or programmatically, it gets nasty fast, so use Business Hours!
Business Hours Name: Tutorial Business Hours
Business Hours: leave default with weekends blank
Add a holiday: April 1st
You do have to activate the Business Hours, so make sure the “Active” checkbox is checked. Don’t know how to do this step, check out this GIF below to walk you through:
Part I: Declarative Approach Using Workflow Rules
We could use workflow rules or process builder to do this step. Tip: there are benefits/limitations to workflow rule vs. process builder, you will be asked about these on the Platform Developer I exam.
Create a new workflow rule with the criteria below. If you need help with this step, check out the gif.
Name: Populate Shipping Date
Description: Workflow rule to calculate and populate the Shipping Date custom field when Case Status changes to Approved.
Evaluation Criteria: created, and any time it’s edited to subsequently meet criteria
Rule Criteria: criteria are met
=> Save, then you can add workflow actions.
Immediate workflow actions: Field update
Name: Calculate the Shipping Date
Unique Name: Calculate_the_Shipping_Date
Data Options: Use a formula to set a new value
=> Click “Save”. Tip: Google Salesforce calculate business hours and you’ll see so many hits, it’s a very common question/application. You can check out example formulas in the Salesforce docs, trailhead, or numerous blogs. We could’ve written the above formula at least a dozen different ways, find one that works for your use-case!
Testing: First, make sure you’ve got the “Shipping Date” field added to the Page Layout. I’m using the “Case Layout” as my org default. If you’re using something else as the default, make sure you’ve added “Shipping Date” to the record. See gif below if you’re unsure how to implement this:
Okay, cool, that was pretty fast! Let’s test it out. Create a new Case record with Status = New and Case Origin can equal anything from the picklist (dropdown menu). Save the record. The Shipping Date field will be blank. Update the record to Status = Approved. The Shipping Date field will populate to today + 2-business days. See the gif below if you’re unsure how to implement this step. Tip: make sure you activate your workflow rule! Click on “Activate” next to the name.
Cleanup time: Don’t forget to deactivate the workflow rule before we move on to the next step!
Part II: Hybrid Approach Using Process Builder and Invocable Apex
First we’re going to go ahead and create a couple Apex classes.
Open the Developer Console and create a new Apex class named “BusinessDays”. Copy and paste in the code below.
Create another class called “CalculateShippingDate”. Copy and paste in the code below.
Create another class for testing called “CalculateShippingDateTest”. Copy and paste in the code below.
Tip: Be sure to run your test either through the Developer Console or from Setup, enter “apex test execution” and select the test class to run. You should have 100% coverage for the CalculateShippingDate class.
Wire it up with Process Builder! Create a new flow with the following criteria, if you are unsure of this step, check out the gif below:
Start the process: when a record is created or edited
Criteria Name: Status = Approved
Criteria for Executing Actions: Conditions are met
Conditions: All of the conditions are met (AND)
Action Name: Calculate the Shipping Date
Apex Class: add two business days
Type: Field Reference
Note: we want the Case record that started the process
Test it — go create a new case and then update the Status to approved, you should see the Shipping Date populate. If you need a reminder on how to do this, check out the gif below.
Cleanup time: Don’t forget to deactivate the Process Builder before we move on to the next step!
Part III Code-based Approach: Using an Apex Trigger on Case
It’s trigger time! What is an Apex trigger? In a nutshell, it’s just a special class that gets invoked after certain events occur on a record. We won’t dig too much into trigger details here, but I will throw in some good practice tips like putting the trigger logic in an Apex class. This helps keep the code clean when you get dozens of triggers on the same object.
Tip: Make sure you have deactivated both the workflow rule and the process builder we created before you do this step!
Open the Developer Console. Create a new trigger named CaseTrigger. Copy and paste in the code below and save.
Create a new Apex class named CaseTriggerHandler. Copy and paste in the code below and save.
Create a new Apex class named CaseTriggerHandlerTest. Copy and paste in the code below and save.
Tip: Run your Apex test class, either through the developer console or from Setup -> Apex test execution. If you get a failure, make sure your trigger is active. Go to Object Manager → Case → Triggers → click on the trigger name and edit. Make sure the teeny, tiny “Is Active” checkbox is checked, see the gif below. You should have 95% test coverage.
Test the trigger. Create a new record and see if the Shipping Date gets populated when the status equals Approved. Try creating a new Case with Status = Approved, check that the functionality works. Try making a new case where Status does not equal Approved, then updating it so the Status does equal Approved, check that the functionality still works.
Clean up: Deactivate that trigger! You do not need extra (active) triggers in your org, not even your developer edition. You’ve still got governor limits, baby!
Wrap up, okay, that was a lot! You did amazing. You’re a natural.
To sum up, working through all 3 of these exercises in one fell swoop, you can get an idea of the pros/cons:
=> Time: warp speed!
=> Potential limitations: our formula works pretty well, but we didn’t tap into the functionality of the BusinessHours Class in Apex, so we miss out on skipping stuff like holidays in our calculations
=>Time: moderate, we had to write a bit of Apex, but not too much
=> Potential limitations: a bit more complex to understand for an admin/developer or developer/admin, but not so bad! Lets’ us tap into the BusinessHours class functionality.
=> Time: well, that depends on your experience and the complexity of the org. Things might be super-fast in your developer edition, you may not have hundreds of workflow rules or dozens of actions being called in one trigger. In a client’s org, you most likely will! Be sure you budget in time for this when implementing this solution for a client.
=> Potential limitations: Code is great, but it’s also less accessible to the client in general. If you can do it declaratively, you should always do that first. If you can’t, try a hybrid or code-only approach!
Okay, we’re all done! Time to enjoy that second breakfast now. I hope this tutorial was useful for you. Please let me know in the comments below if you have any questions or feedback.