Wednesday, April 1, 2015

Events Created By Apex Respects DST

For my own edification, I wanted to confirm that Apex in Salesforce is capable of automatically adjusting for DST based on the user's local time zone.

The scenario: As a user in the America/New_York time zone, when I create an event using Apex for July 4, 2015 (EDT) at 9:00 AM and another event for December 25, 2015 (EST) at 9:00 AM, I expect the following:

  • Both events should appear in the UI as starting at 9:00 AM on my calendar
  • The UTC start time for the July 4 event should be 13:00
  • The UTC start time for the December 25 event should be 14:00, which accounts for the end of Daylight Savings Time

The following code confirms the expected behavior:

Thursday, February 12, 2015

Queueable vs. @future throwdown!

At first blush, the new Queueable interface appears to supersede the old @future annotation in Apex, especially now that in Spring '15 you can chain a job to another job an unlimited number of times. Yes, that's right: unlimited.

So, what's the purpose of @future in this new age of Apex?

Let's start by comparing the well known @future limits with Queuable.

@future consideration vs. Queueable
Some governor limits are higher, such as SOQL query limits and heap size limits Some governor limits are higher than for synchronous Apex, such as heap size limits
Methods with the future annotation must be static methods Queueable implementations must be instantiated as objects before the the execute() instance method is called, leaving room for additional job context
Methods with the future annotation can only return a void type Queueable classes must implement public void execute(QueueableContext), which is how a job is initiated
The specified parameters must be primitive data types, arrays of primitive data types, or collections of primitive data types. Methods with the future annotation cannot take sObjects or objects as arguments. A Queueable object can be constructed with any type of parameter, stored as private member variables
Can make a callout to an external service
A future method can’t invoke another future method You can chain queueable jobs. You can add only one job from an executing job, which means that only one child job can exist for each parent job.
No more than 50 method calls per Apex invocation You can add up to 50 jobs to the queue with System.enqueueJob in a single transaction
The maximum number of future method invocations per a 24-hour period is 250,000 or the number of user licenses in your organization multiplied by 200, whichever is greater. This is an organization-wide limit and is shared with all asynchronous Apex: Batch Apex, Queueable Apex, scheduled Apex, and future methods. The licenses that count toward this limit are full Salesforce user licenses or Force.com App Subscription user licenses.

From the reverse side, what about known limits with Queuable?

Queueable consideration vs. @future
The execution of a queued job counts once against the shared limit for asynchronous Apex method executions.
You can add up to 50 jobs to the queue with System.enqueueJob in a single transaction. No more than 50 method calls per Apex invocation
No limit (except in DE and Trialforce orgs) is enforced on the depth of chained jobs, which means that you can chain one job to another job and repeat this process with each new child job to link it to a new child job. n/a (cannot chain @future methods)
When chaining jobs, you can add only one job from an executing job with System.enqueueJob, which means that only one child job can exist for each parent queueable job. Starting multiple child jobs from the same queueable job isn’t supported.
You can’t chain queueable jobs in an Apex test. Doing so results in an error. To avoid getting an error, you can check if Apex is running in test context by calling Test.isRunningTest() before chaining jobs.

The verdict: Implement Queueable as a standard approach, and only look to @future if for some reason Queueable gives you unexpected or undocumented problems.

Friday, January 9, 2015

$Action.Contact.AddToCampaign explained

Recently a question came up about using $Action.Contact.AddToCampaign on a Visualforce page. The common usage pattern below for $Action variables does not work as expected.

So, I logged a case with Salesforce to get an explanation for how $Action.Contact.AddToCampaign is supposed to work. And the eventual answer I received after three weeks was very surprising.

In short, the merge variable only works when used as the action value in a form element. Let me illustrate this with the sample Visualforce code below.

The unfortunate answer at this point seems to be that $Action.Contact.AddToCampaign only works if you want to use it inside a custom HTML form, not an apex:form. salesforce.com's recommendation is to use $Action.Campaign.AddCampaign instead, which in my opinion defeats the purpose of easily launching a native wizard to add the contact in a given context to a user-specified campaign.

Tuesday, December 30, 2014

Salesforce logo sizes

Here's an aggregation of standard logo sizes to consider for use with various Salesforce components.

Salesforce standard logo sizes
Placement Width x Length (px) Max File Size (kB)
custom app logo 300 x 55 20
My Domain login page header 250 x 125 100
community login page header 250 x 125 100
Salesforce1 app branding 150 x 50 none
community Chatter email logo 460 x 560 none

Sunday, December 21, 2014

Where's the Visualforce viewstate coming from?

I felt inspired by a Q&A on Salesforce Stack Exchange to explore the growth of viewstates in Visualforce under different conditions. Without even reaching all of the test cases I originally set out to investigate, I was extremely surprised by my initial findings:

  • A viewstate only gets created once an apex:form is added to the page, regardless of what controller, if any, is used; but more curiously...
  • A viewstate grows when non-form elements outside the apex:form are added to the page! How? And why?


So while I wait for a response from the case that I'm going to log with Salesforce Support, I welcome anyone else's explanation for this phenomenon. Below are the Visualforce pages that support my findings above.

Visualforce viewstate exhibits
Number Title Observations
Exhibit 1 No controller, no form No viewstate
Exhibit 2 Standard Lead controller, no form No viewstate
Exhibit 3 Custom controller with persistent property, no form No viewstate
Exhibit 4 No controller, one form There's a viewstate! Which seems odd, since there's no controller to process the viewstate.
Exhibit 5 No controller, two forms There's a single viewstate that's slightly larger than what's in Exhibit 4.
Exhibit 6 No controller, two forms There's a single viewstate that's slightly larger than what's in Exhibit 5, even though literally nothing has changed except for the addition of a new p element outside of the apex:form!

I've posted the source code for the Visualforce pages to GitHub as a gist.

Friday, December 12, 2014

Workflow rule to record prior Owner Name

Sometimes you want to record a prior (a.k.a. "old") value for a particular field when it changes. If you need this simply for auditing purposes, tracking field history or implementing feed tracking should be all you need. But an alternative is needed if you want to do something else with that prior value, such as presenting it on a report or using it in a formula field.

The easiest way to record the prior value for something like Owner ID (could be Lead, Account, etc.) is to create a workflow rule and field update that uses the PRIORVALUE() function.

To see this in action, try the following to store the prior Lead Owner ID:

  1. Create a Text(80) field on the Lead object named PriorLeadOwnerId
  2. Create a workflow rule named, "Set Prior Lead Owner ID". For evaluation criteria, select "Evaluate the rule when a record is created, and every time it’s edited". For rule criteria, enter this simple formula: ISCHANGED( OwnerId )
  3. Add a new field update action to the workflow rule named PriorLeadOwnerName, which updates the Prior Lead Owner Field by setting it to the formula: PRIORVALUE( OwnerId )
  4. Activate the workflow rule

Tip: If you want store prior related values, such as Owner Name instead of Owner ID, you can actually use a formula field to work around a PRIORVALUE() limitation.

For example, you can create a formula field labeled Lead Owner Name with formula, BLANKVALUE( Owner:Queue.Name , Owner:User.FirstName + ' ' + Owner:User.LastName ), and then use this formula field in the above workflow rule instead of OwnerId.


At this time, workflow rules still cannot set a Lookup field to a dynamic or formulaic value. So while a workflow rule certainly is convenient, it's important to remember that in Winter '15 there are a couple of other more powerful alternatives. 
  • Lightning Process Builder: Beta feature that seems poised to replace workflow rules once it becomes GA.
  • Apex triggers: Nothing quite beats the power and precision of an Apex trigger, But you will need to learn some new syntax and guidelines.

Tuesday, December 9, 2014

Checkbox field for Live Agent pre-chat form

A [simple question](http://salesforce.stackexchange.com/questions/58529/live-agent-pre-chat-api-custom-checkbox-field/58533#58533) on Salesforce Stack Exchange exposed some unexpected behavior with the Pre-Chat API: Checkbox fields cannot be included as part of the pre-chat form.

The behavior appears to be that if a checkbox field is added to the specification for liveagent.prechat.findorcreate.map and liveagent.prechat.findorcreate.map.doCreate, the creation process fails and the desired record is not created. As soon as the checkbox field is removed from the form definition, the record creation process executes as expected.

While the reason for this behavior is unclear, at least there are two possible workarounds. The key to both workarounds is knowing that the String value of a marked checkbox is "on", and the String value of an unmarked checkbox is blank or null.


Workaround 1: Workflow rule


Assuming you've already created your Checkbox field, you can create a complementary Text field to hold the checkbox value submitted through the pre-chat form. For example, let's say your Checkbox field is named IsEmployed__c. You can create a Text field named IsEmployedText__c, and bind the pre-chat form field to IsEmployedText__c.

To close the loop, you'll create a workflow rule that basically sets IsEmployed__c to true when IsEmployedText__c equals "on", and another workflow rule to set IsEmployed__c to false otherwise.

Workaround 2: Formula field


Start with a Text field, and then simply create a Formula (Checkbox) field that uses NOT( ISBLANK( __ ) ) to produce the equivalent Boolean value.

For example, create a Text field named IsEmployedText__c, and bind the pre-chat form to this field. Within Salesforce, create a Formula (Checkbox) field named IsEmployed__c, and put int he formula NOT( ISBLANK( IsEmployedText__c ) ).