May 22, 2013

Salesforce SMS Identify Confirmation

Salesforce has recently rolled out a change that affects the default identity confirmation setting and user confirmation process for your org(s). They began this change in March, issuing a new CRUC (CRitical Update Console - ) that automatically applied May 1st.

Identity Confirmation comes into play when you are logging into an org for the first time either from a new device or from a new location.  When doing so, you'll be prompted with this screen after putting in your password:

Receiving this verification code by email was the default setting.  After the critical update, the default method for receiving the code was by SMS.  After the update was applied, upon logging in again, you may have been prompted with this screen:

That screen will only appear for users that don't have a verified mobile phone listed on their user record.  After providing it and clicking on the "Send me a text message," the user will receive a short numeric code via text message.  If a user doesn't have a mobile phone, they can decline, using the "No thanks..." link and continue to use email verification.

After receiving your code, return to your Salesforce login and enter the code.  You won't have to do this again unless you log in using a new device or from a new location.

Take note that there is a new System Permission that will allow you to enable email-based identity confirmation for users (those w/ verified phone numbers).  This is useful in those scenarios where a user suddenly does not have access to their text messages.  This can be applied within a profile or within a permission set (recommended):

More details from Salesforce here:

Syncing Salesforce Changes to an External System with Future/Schedule Architecture

Many integration projects involve syncing Salesforce data to external systems. For example, you may need to sync contacts and leads along with their related events and tasks to a home-grown portal, or sync financial information to an external accounting system, or sync sales data to a system that allows better mobile experience for certain verticals.

The business logic for some of these projects is very complex, but the general design of the solution usually follow known patterns. However, certain requirements present several considerations that make writing the more common integration code a bit trickier. Here are a few such considerations:
  • Sync events get fired by triggers, but triggers can’t make callouts, so syncing code must run asynchronously (@future).
  • Trigger execution order is not guaranteed, so it is possible that your sync trigger will be fired by a process that is already running asynchronously (which will create a runtime error).
  • Depending on the activity and the number of objects that get synced, you can reach callout limits.
  • Packaged sync applications often clash with other packages that also work asynchronously. Packaged apps also have wide variability of activity, so there is a good chance to hit callouts limits.
  • Any runtime error results in a sync event that is not transmitted to the external system.
  • Any delayed process needs to run soon after the triggering event occurred. Also, a record that is triggered again before its delayed processing occurs, should not be transmitted twice (unless needed by the external system).

To avoid some of these issues, or at least make it less likely for a transaction to be lost, I’ve come up with a design pattern that combines both almost-immediate (future) and delayed (scheduled) methods to communicate with external systems that need to be synced. The basic idea for this design pattern is to always try the immediate processing as the first option, but also allow for a scheduled job to be created if immediate processing is not possible at the time.

Here’s how it’s done… Please note, that I omitted (added as a comment) any business logic that is not important for the design pattern.

First of all, create two new objects to handle scheduled syncing:
  • An object called Synchronize__c to hold Ids of records that need to be synced, as well as any additional information that is needed when processing jobs. For example you may want to save the type of trigger that fired the sync event (insert or update). This object will be queried by a scheduled process, and allow the scheduled processing to reuse the normally triggered sync code.
  • An object called  CronJob__c to hold Cron Job Ids so we can keep track of what jobs were created and be able to remove them after they execute. This is necessary because querying the cron job object does not give you all the info you need to clean up old jobs.

Next, create a schedulable class called SynchronizeSched.cls that will be used to execute scheduled code. Keep it empty until the rest of the code is written:

Next, create a class (Synchronize.cls) to handle all the business logic and special processing. The next four methods will be added to this class, starting with a static class called ProcessFutureCallout that receives a set of Ids. Since the execution is starting from a trigger, specify @future(callout = true) before the method declaration to allow the class to make a callout. This method is what you would normally write to sync records to an external system, and will include any business logic that needs to run before the callout, the actual callout, and the response handling.

Now we can create a method called ScheduleCallout that can handle the delayed sync. This method will be called instead of ProcessFutureCallout when an asynchronous call cannot be made immediately. Within the method, we need to save the Ids of all the records that need to be synced, as well as any other important info, to the newly created object Synchronize__c. Then, create a cron job and save its Id to the new object CronJob__c. Note that in this example, the job is scheduled 1 to 2 minutes into the future. By adding two minutes to now, the scheduled job will run on the second to next whole minute. I think that this is the shortest time period that should be scheduled because if you add just one minute to now(), you run the risk that the code would execute around a whole minute and create a job that cannot be scheduled (You'll get the error "Based on configured schedule, the given trigger will never fire"). Of course, the delayed job can be scheduled for an hourly or daily sync. Not included in the sample, but a good addition, is a quick check that a scheduled job is not already created before creating a new one.

Now create a method ProcessTrigger to be used as the entry point from the trigger. At the beginning of the method, add the normal logic that figures out if you need to process the changed record(s). Once you know which records need to be synced, you can figure out if it is possible to continue processing asynchronously. If it is not possible, you can schedule the changed records for later execution. This method can check for all kind of governor limits and react as needed.
We have to create one more method called ProcessScheduledCallout to handle the scheduled logic. The schedulable class will call this method to run the delayed sync. This method actually does not do much other than get info from the database, call ProcessFutureCallout, and then clean up the database. Since ProcessFutureCallout already has all the logic we need, there is no point rewriting that here.
Lastly, update the schedulable class from the first step to call the ProcessScheduledCallout() method:

May 20, 2013

Parsing JSON \/Date to Salesforce Datetime

If you're working on a lot of custom integrations, you are bound to eventually see dates and datetimes that are represented like this: "\/Date(1198908717056)\/". These dates show up in JSON as strings, and their numeric value represent milliseconds since January 1st 1970 UTC. I believe that this is a Microsoft standard mostly used by .net to represent epoch time.

Here's a quick and useful method that parses these ".net type" datetimes into salesforce datetimes. Simply parse out the numeric value using the parenthesis as guides, cast as long, and use the very useful datetime method newInstance() to calculate the actual date.

May 13, 2013

Reports: Export Details VS Printable View

Ever generate a report, click on the "Export Details' button only to find out that once opened in Excel, the report looks nothing like what you saw in your browser window. What's going on here?

Here's a very simple Contact report grouped by Contact Owner.  You can see there is a distinct grouping by Owner (dark blue bar).

However, when you click on "Export Details," this is what you get:

The "Export Details" button does exactly that... it exports the details of the report; meaning every line that makes up your report will be rendered as a new line in your .xls or .csv. This is regardless of whether or not you have clicked on the "Show Details" or "Hide Details" button. Of course, you could rework the resulting spreadsheet and do the grouping yourself, but why would you do that?

Rather than eagerly clicking on the "Export Details button," take the "Printable View" button for a test drive. It will render your report again as an .xls file, but retain the grouping as you see it on your report.

Here's the same report, exported with the "Printable View" button:

If you want to see the details, click on the "Show Details" button prior to clicking on the "Printable View" button. This will show each line item as well as the summarized headers. If you don't want details, make sure that you've clicked on the "Hide Details" button.

Note that when you choose "Export Details," you are prompted to chose an export file encoding format (ISO, Unicode, etc) and export file format (.csv or .xls).  If using the "Printable View" option, you will always get a .xls file.  Within your spreadsheet editor, you can always choose to save with another file extension and encoding format.

In case you were wondering, this also works for Matrix reports!

May 8, 2013

Download Our Chrome Extension: Admin Assistant

Our Admin Assistant extension provides administrators (and developers!) with additional time-saving tools and settings shortcuts to facilitate the day to day functions and responsibilities they may be faced with.

If you attended the PhillyForce meetup during Philly Tech Week, you may have seen my session on my Salesforce Chrome Extensions.  If you didn't, check out the recorded demo of that session at the bottom of this post.

As user, have you ever had the feeling that "there should be an easier way" or have stared at a long list of check boxes and thought, "I have to do this for every one of these?"  These are the reasons I created the Admin Assistant extension.

Here's a subset of the features included in Admin Assistant v1.0:

Mass Delete:  On List Views, you often have a series of records with checkboxes next to them.  Natively, there is no "Delete" option that will wipe out the selected records with one click.  This feature will delete any of the selected records.

Maybe you're testing a new piece of Apex code or building out a new workflow that generates a lot of junk records.  How many times have you wanted to delete a few of these records and been in this situation?

Deleting each of the four Contact records above would require you to click on the "Del" link on each row, confirm that you want to delete the record, rinse, and then repeat multiple times.

Show Max Results:  Show Max - on pages that list schema components like workflow rules, actions, and email templates, there is often a "Show More" link.  This feature displays a maximum number of the possible results on one page with one click.

Chatter Chat:  If Chatter is enabled in your org, a floating "Chat Window" appears in the bottom right hand corner of your screen.  This can be turned on or off.

Various Profile Settings:  At the field level, check or uncheck all of the "Visible" or "Read-Only" boxes.  At the Object level, check or uncheck all of the CRUD/View All/Modify All boxes.  For Tabs, quickly display or hide all Salesforce tabs.


Here's the demonstration from our Philly Tech Week '13 PhillyForce Meetup:

Download it here:
Admin Assistant in the Chrome Web Store
Admin Assistant on the AppExchange