Menu Bar

Friday 30 November 2012

Maximizing Your Strategy for Social Customer Service



Do you know how useful unique IDs are to your development effort?


15 or 18 Character IDs in Salesforce.com – Do you know how useful unique IDs are to your development effort?

Data can be empowering or devastating.  Unique IDs can enrich your data and make your life significantly easier.  We have taken the concept of using IDs as quick means to locate data (in part 1 of this blog post) and navigate around Salesforce.com, one very big step forward.
You’ve probably also noticed that these IDs are either 15 or 18 characters; however do you know why? A nice example is a standard report look up, where they’ll show up as 15 characters, take a look below:
If you aren’t following this, let’s take the opportunity to take a step back and point out a previous conversation.
If you are still with me, then we are going to explore a few tips and tricks to add some value to your data.
Salesforce.com IDs are case-sensitive so if you wanted to export data to Excel to be used as a lookup table using the VLOOKUP formula, you’ll need to be aware of this. If you happened to have records with IDs of 001A0000006Vm9r and 001A0000006VM9r the VLOOKUP formula, not being “case-aware”, would always find the first record, regardless of the case of the lookup value. Salesforce.com realized the potential problem with this and instigated the 18-character ID.
There was a method to their madness of expanding out by three additional characters. They are similar to “checksum” values in that they were calculated based on 15 character IDs. They gave these IDs what they needed – the ability to be different if the case of ANY of the first 15 characters changed.
More importantly, the addition of 3 characters allow for upward-compatibility.  Salesforce made the two types of ID interchangeable.
You could use either ID and they would be regarded as identical, at least within Salesforce.com applications. This was carried forward when the Apex programming language was made available.
For example, when you compare two fields of type “Id”, the values are first converted internally to 18-character values before being compared, so you never need to worry about programming specifically to handle this (this is very useful for developers)

Let’s get technical…

The next part of this article assumes a good working knowledge of the following:
  • Force.com Apex language constructs and syntax
  • Apex triggers and classes
  • Apex test methods, code coverage and unit tests
  • How to add code to your org using an IDE e.g. Eclipse & the Force.com plugin
This highlights one source of annoyance to many users – reports do not show 18-character IDs.
If Salesforce had provided a function to return an 18-character field from an existing ID, that might have given us enough to achieve a “formula field workaround”, but they didn’t. In lieu of a formal workaround I will give you this, albeit in a more technical form.
First, I’ll show you how to attach an Apex trigger to an object, to give you an identical result. With this, every time a record is added to the system, an 18-character (text) field is updated with the 18-character equivalent ID, calculated by the trigger.
Salesforce provide the algorithm they use for this, but not the code. So, here’s the code. Diagrams make things easier, so as you read, here is a mock up of the process:
  • In Step 2, the characters are reversed in each piece.
  • In Step 3, we check each character. If the character is uppercase A to Z, we replace it with a 1, otherwise we replace it with a 0 character.
  • In Step 4, we lookup the above table with each of the three 5-character “binary” string.
  • And finally, in Step 5 we simply append these three characters onto the end of the original ID value.
The clever thing about this is that the algorithm will always change the value of the additional 3-characters if you change the case of any of the original ID characters.
The Code
And now for the code – this assumes a familiarity with Apex code, the Eclipse environment, how triggers work and a little bit of Salesforce.com knowledge.
I’ve created a class called Utility – you can call it what you like. We will create a static method called sfdc15To18
Now, copy the following code into the body of your class file:

public static String sfdc15To18 (String original15) {
// This method expects a 15-char valid Salesforce ID, and returns the 18-char equivalent
Map<String,String> lookup5bin = new Map<String,String>();
String Piece1 = '';
String Piece2 = '';
String Piece3 = '';
original15 = original15.substring(0,15);
lookup5bin.put('00000','A'); lookup5bin.put('01000','I'); lookup5bin.put('10000','Q'); lookup5bin.put('11000','Y');
lookup5bin.put('00001','B'); lookup5bin.put('01001','J'); lookup5bin.put('10001','R'); lookup5bin.put('11001','Z');
lookup5bin.put('00010','C'); lookup5bin.put('01010','K'); lookup5bin.put('10010','S'); lookup5bin.put('11010','0');
lookup5bin.put('00011','D'); lookup5bin.put('01011','L'); lookup5bin.put('10011','T'); lookup5bin.put('11011','1');
lookup5bin.put('00100','E'); lookup5bin.put('01100','M'); lookup5bin.put('10100','U'); lookup5bin.put('11100','2');
lookup5bin.put('00101','F'); lookup5bin.put('01101','N'); lookup5bin.put('10101','V'); lookup5bin.put('11101','3');
lookup5bin.put('00110','G'); lookup5bin.put('01110','O'); lookup5bin.put('10110','W'); lookup5bin.put('11110','4');
lookup5bin.put('00111','H'); lookup5bin.put('01111','P'); lookup5bin.put('10111','X'); lookup5bin.put('11111','5');
Piece1 = sfdc0Or1(original15.substring(4,5)) +
sfdc0Or1(original15.substring(3,4)) +
sfdc0Or1(original15.substring(2,3)) +
sfdc0Or1(original15.substring(1,2)) +
sfdc0Or1(original15.substring(0,1));
Piece2 = sfdc0Or1(original15.substring(9,10)) +
sfdc0Or1(original15.substring(8,9)) +
sfdc0Or1(original15.substring(7,8)) +
sfdc0Or1(original15.substring(6,7)) +
sfdc0Or1(original15.substring(5,6));
Piece3 = sfdc0Or1(original15.substring(14,15)) +
sfdc0Or1(original15.substring(13,14)) +
sfdc0Or1(original15.substring(12,13)) +
sfdc0Or1(original15.substring(11,12)) +
sfdc0Or1(original15.substring(10,11));
return (original15 + lookup5bin.get(Piece1) + lookup5bin.get(Piece2) + lookup5bin.get(Piece3));
}
private static String sfdc0Or1 (String charX) {
// This method accepts a one-char string and returns '1' if it's between A and Z, otherwise '0'.
if (charX.compareTo('A') >= 0 && charX.compareTo('A') <= 25 && charX.compareTo('Z') >= -25 && charX.compareTo('Z') <= 0) return '1';
return '0';
}
public static testMethod void Test15_to_18_a() {
// For the test methods, I've taken three values where I manually calculated the additional 3 chars expected
String orig1 = '001A0000006Vm9r';
System.AssertEquals(orig1+'IAC',sfdc15To18(orig1));
String orig2 = '003A0000005QB3A';
System.AssertEquals(orig2+'IAW',sfdc15To18(orig2));
String orig3 = '003A0000008qb1s';
System.AssertEquals(orig3+'IAA',sfdc15To18(orig3));
}
The code is made up of one main method, sfdc15To18. I’m not going to go into too much detail as I’ve already described the process above, and I don’t think the code is too hard to follow. There is a comment for each method, that should be sufficient. It will give you 100% code coverage and no failures.
One final thing remains, I just need to show you how to use this method in an Apex trigger to keep a custom field updated with the 18-character value. The trigger is quite simple. First, create a new custom 18-character text field to hold the value (there is no reason to add this field to a page layout, unless you really want to):
Here is the trigger code (on the Account object) and the associated Utility class method:

trigger AccountID18 on Account (after insert) {
// This trigger must be after insert, as no ID values are available before insert.
// This means we must update the trigger records explicitly as a batch.
// One other problem, because the system locks the records, they must be updated in an
// asynchronous (@future) method. We will pass a list of IDs to an @future method.
// You will need to write your own test method code for this code.
List<Id> lstId = new List<Id>();
for (Account iAcc : Trigger.new) {
lstId.add(iAcc.Id);
}
Utility.updateAccountId18(lstId);
}
…and the associated Utility class method…

@future
public static void updateAccountId18(List<Id> IDsToUpdate) {
List<Account> lstAcc = new List<Account>();
for (Id iID : IDsToUpdate) {
Account wrkAcc = new Account(Id = iID, ID18__c = Utility.sfdc15To18(String.valueOf(iID)));
lstAcc.add(wrkAcc);
}
update lstAcc;
}
You can now go ahead and generate reports using the new 18-character ID fields. If you Export them to Excel you’ll have no problems using VLOOKUP (or similar) functions.
One minor point I should mention: @future methods may not always run immediately (but typically do), and in extreme cases there may be a few minutes wait before they update your data. Bear this in mind when you are testing!

Alternatives…

There are alternative ways of doing the same thing. You could install the Excel Connector:
Follow the instructions to set this up and you now have a new inbuilt Excel function called FIXID available. You can enter a formula such as:
=FIXID(B2)
… and this will give you an 18-char ID using the same algorithm. If you have problems installing this (or you just don’t want to), and you have some Excel/VBA expertise, you could add this code to your Excel installation:

Function FixID(InID As String) As String
If Len(InID) = 18 Then
FixID = InID
Exit Function
End If
Dim InChars As String, InI As Integer, InUpper As String
Dim InCnt As Integer
InChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
InUpper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
InCnt = 0
For InI = 15 To 1 Step -1
InCnt = 2 * InCnt + Sgn(InStr(1, InUpper, Mid(InID, InI, 1), vbBinaryCompare))
If InI Mod 5 = 1 Then
FixID = Mid(InChars, InCnt + 1, 1) + FixID
InCnt = 0
End If
Next InI
FixID = InID + FixID
End Function
Or if you are working with 15-char Ids in a Microsoft SQL Server database, you can find a T-SQL function at this address:
And Ron Hess, Salesforce Evangelist, has posted the code for a JavaScript equivalent function here:
The very best of luck!

Wednesday 28 November 2012

Real-time push notifications from Force.com to Heroku using WebSockets

Real-time push notifications from Force.com to Heroku using WebSockets

This is the third and final post in a series that reviews Social Web-to-Lead, a Node.js Facebook application running on Heroku that integrates with Force.com. My first post covered the basic application use case and its use of the REST API to insert Lead data in Salesforce from the Facebook application. The second post described the use of the Redis Heroku add-on and Apex REST to implement a more efficient design for the application that consumed fewer Force.com API calls. In this post I want to describe how Social Web-to-Lead implemented real time push notifications from Force.com to Heroku using HTML5 WebSockets. The entire application codebase is available here and you can also watch a recording of the Dreamforce 2012 session where I demoed the application.

Use Case

The primary use case for Social Web-to-Lead was to allow Facebook users to enter their contact information via a ‘Contact Me’ link (typically from the company/brand Facebook Page). That information was then captured as a Lead record in Salesforce via a Force.com REST API call. Imagine a use case where the data flow is reversed. In other words, say that you need to ‘push’ some data updates from Force.com to the Facebook application in real-time. Specifically for Social Web-to-Lead, say that a Force.com Custom Object (Offer__c) stores special customer offers and you want your Facebook application to display new offers as soon as they’re added in Force.com (without requiring a browser refresh). To make it a little more interesting, we’ll display the offers as QR Codes that your Facebook users/fans can print and bring to the physical store. This screenshot shows how this would look like to the Facebook users who click the ‘Exciting Offers’ link on the company/brand Facebook Page (screenshot on the left)  .
Every time that a new offer record is added in Salesforce, the offers page shown on the right would automatically display the new QR encoded offer (without requiring a browser refresh). You can also skip to this point in the session recording to see this real-time push notification in action.

Integration Architecture

The figure on the right shows the high-level architecture for the real-time push integration between Force.com and Heroku. We’re using a great Heroku add-on called Pusher to send the push notifications to the web page. Every time that a new offer is inserted in Salesforce, an Apex trigger make an HTTP callout to the Pusher REST API and sends over the offer details. Pusher does the rest. It uses WebSockets to push the offer data to the offer.ejs web page in the Heroku application where we use some simple JavaScript to generate a QR code for the offer.

Streaming API – where art thou?

Before we dive into the Pusher based architecture described above, lets address an important question. The use case described above requires real-time push notifications from Force.com to an external web application. That’s an ideal use case for using the Force.com Streaming API. There is one thing about this use case however that precludes the use of the Streaming API. Like all other Force.com APIs, the Streaming API requires authentication with Salesforce before a client can start receiving push updates via the API. In our use case however, the client is a Heroku-hosted web page that is surfaced as a Facebook application. None of the Facebook users will have an equivalent Salesforce identity in this use case and so we cannot authenticate with the Streaming API. For such unauthenticated push notification use cases, an intermediary service like Pusher may be considered.

Adding Pusher to the Heroku application

Lets start our deep dive into the integration design by reviewing how you can use the Pusher add-on in a Heroku application. As with all Heroku add-ons, its as simple as running the following command
1$ heroku addons:add pusher:sandbox
from the Heroku CLI tool. This will provision a free developer/test account for you on the cloud based Pusher service. Next, in order to receive the WebSockets notifications on your web page, you have to add a couple of lines of JavaScript code to your page. Here is a snippet from the offers.ejs page of the Social Web-to-Lead application that shows that code
01
And with just those 10 lines of JavaScript code, you’re ready to receive real-time push notifications from Pusher. As part of initializing the Pusher JS library, you’ll need to pass in the unique Application Key assigned to your application by Pusher (line 2). After installing the Heroku add-on, simply login to your Heroku account, select your Heroku app and then click on the ‘Pusher Sandbox’ Add-on. Select the ‘API Access’ tab and you’ll find your unique application key to include in the JS code. Pusher uses the concept of  binding to specific ‘events’ on a ’channel’ (lines 3, 4). Once we get notified of a new offer event via Pusher, we QR encode the offer data using a simple JQuery plugin (line 8 ) and add the resulting image to the page DOM.

Sending push notifications to Pusher from Force.com

Lets complete the circle by reviewing how we push new offers to Pusher from Force.com. It starts with a simple trigger on the Offer__c custom object.
1trigger PushOfferNotification on Offer__c (after insert) {
2 
3    OfferNotificationToPusher.sendPusherNotification(trigger.newMap.keySet());
4}
As experienced Force.com developers know, you can’t make synchronous callouts directly from an Apex trigger. Instead, you use a @future annotation to execute the callout logic asynchronously from the main trigger execution thread. That’s exactly what the OfferNotificationToPusher class does. Here’s a snippet from that class.
01public class OfferNotificationToPusher {
02    public static final String pusherApiURL = 'http://api.pusherapp.com';
03    public class Offer{
04        Decimal num;
05        String text;
06        public Offer (Decimal n, String t){
07            num = n;
08            text = t;
09        }
10    }
11 
12    @future (callout=true)
13    public static void sendPusherNotification(Set> offerIds) {
14        JSONGenerator gen = JSON.createGenerator(true);
15        List> offers = new List>();
16        gen.writeStartObject();
17        for (Offer__c o : [select Offer_Number__c, Offer_Description__c fromOffer__c
18                           where id in : offerIds
19                           and status__c = 'Active']){
20            Offer off = new Offer(o.Offer_Number__c, o.Offer_Description__c);
21            offers.add(off);
22        }
23        gen.writeObjectField('offers',offers);
24        gen.writeEndObject();
25 
26        String notificationString = gen.getAsString();
27 
28        PusherConfig__c config = PusherConfig__c.getAll().values()[0];
29        String pusherApiURI = '/apps/'+
30                              config.Pusher_App_Id__c +
31                              '/channels/'+config.Pusher_Channel__c +
32                              '/events';
33        Long now = Datetime.now().getTime() / 1000;
34        String pusherQueryString =  'auth_key='+config.Pusher_Key__c+'&auth_timestamp='+now+
35                                '&auth_version=1.0&body_md5='+
36                                EncodingUtil.convertToHex(Crypto.generateDigest('MD5',
37                                                          Blob.valueOf(notificationString)))+
38                                '&name=new_offer';
39        String stringToEncode = 'POST\n'+pusherApiURI+ '\n'+ pusherQueryString;
40        String sig = EncodingUtil.convertToHex(Crypto.generateMac('hmacSHA256',
41                                               Blob.valueOf(stringToEncode),
42                                               Blob.valueOf(config.Pusher_Secret__c)));
43 
44        String finalPusherApiURL = pusherApiURL + pusherApiURI + '?' +
45                                   pusherQueryString + '&auth_signature=' + sig;
46        HttpRequest req = new HttpRequest();
47 
48        req.setEndpoint(finalPusherApiURL);
49        req.setMethod('POST');
50        req.setHeader('Content-Type', 'application/json');
51        req.setBody(notificationString);
52 
53        Http http = new Http();
54        HTTPResponse res = http.send(req);
55    }
56}
The sendPusherNotification uses the native Apex JSON library and a simple ‘wrapper’ inner class (Offer) to translate the offer data into the appropriate JSON format for the Pusher REST API (lines 14-26). The Pusher API requires a very specific form of authentication and that is what lines 28-45 are doing. Notice also how the authentication code uses a Custom Setting (PusherConfig__c) to store the Pusher App id, key and secret assigned to your application. Once the Apex trigger invokes the above callout logic, Pusher takes care of propagating that offer data to all browser clients that are currently displaying the offers.ejs page of the Heroku application.
Hopefully this blog series have gotten your creative juices flowing on what’s possible when you combine the power of Facebook, Heroku and Force.com. If you have any other interesting use cases for such enterprise-focused social applications, please share them via the comments section.