Business Case:
Recently I was working on a project where data integration was pushing bunch of order records into salesforce.Order was represented as a custom object in salesforce. It had a phone number field where obviously phone number was getting inserted. The problem was that the phone number was not getting formatted properly when inserted in salesforce. For example when you add this phone number (5555555555) in the phone number field in standard salesforce UI, it gets converted to (555) 555-5555.
But this doesn't happen when you insert the records using API.
We were using a phone number value to match the orders with Opportunity's phone number field which had formatted phone value. So, we needed to format the phone number correctly when inserted in the Order object's phone number field. So , that it is consistent and we can use it to match. You can't match 5555555555 to (555) 555-5555 .
I needed to know how salesforce handles different kind of input in that phone field and how do they format it.So that I can replicate the same thing in apex as well.
After some investigation I found out this javascript methods in salesforce which formats the phone number field when the focus loses on the phone number field in standard UI.
And here is the apex equivalent of that method in PhoneFormatter class:
I could have probably used Regular Expression which might have reduced number of script statements. But since salesforce has no more limit on the number of script statements per execution I think this is a good solution and it has been working fine in the org where it is processing 200 phone numbers at a time in a batch of 200 orders. I call this apex method on the before insert trigger.
Here are the different test cases I tested with the above method.
I hope you find it useful.
Recently I was working on a project where data integration was pushing bunch of order records into salesforce.Order was represented as a custom object in salesforce. It had a phone number field where obviously phone number was getting inserted. The problem was that the phone number was not getting formatted properly when inserted in salesforce. For example when you add this phone number (5555555555) in the phone number field in standard salesforce UI, it gets converted to (555) 555-5555.
But this doesn't happen when you insert the records using API.
We were using a phone number value to match the orders with Opportunity's phone number field which had formatted phone value. So, we needed to format the phone number correctly when inserted in the Order object's phone number field. So , that it is consistent and we can use it to match. You can't match 5555555555 to (555) 555-5555 .
I needed to know how salesforce handles different kind of input in that phone field and how do they format it.So that I can replicate the same thing in apex as well.
After some investigation I found out this javascript methods in salesforce which formats the phone number field when the focus loses on the phone number field in standard UI.
function formatPhone(a) {
a.value = trim(a.value);
var b = a.value,
c = "",
d = -1;
if (0 < b.length && "+" != b.charAt(0)) {
var e = 0;
if ("1" == b.charAt(0)) b = b.substring(1, b.length);
for (i = 0; i < b.length; i++) {
var f = b.charAt(i);
if (f >= "0" && f <= "9") {
if (e == 0) c += "(";
else if (e == 3) c += ") ";
else if (e == 6) c += "-";
c += f;
e++
}
if (!(f >= "0" && f <= "9") && f != " " && f != "-" && f != "." && f != "(" && f != ")") {
d = i;
break
}
}
if (d >= 0) c += " " + b.substring(d, b.length);
if (e == 10 && c.length <= 40) a.value = c
}
return true
}
And here is the apex equivalent of that method in PhoneFormatter class:
public with sharing class PhoneFormatter {
static Map < String, Integer > stringNumberToIntegerMap {
get {
if (stringNumberToIntegerMap == null) {
stringNumberToIntegerMap = new Map < String, Integer > {
'0' = > 0, '1' = > 1, '2' = > 2, '3' = > 3, '4' = > 4, '5' = > 5, '6' = > 6, '7' = > 7, '8' = > 8, '9' = > 9
};
}
return stringNumberToIntegerMap;
}
set;
}
public static String formatPhone(String phoneNumber) {
String formattedNumber = phoneNumber;
String trimmedPhone = phoneNumber.trim();
List < String > c = new List < String > ();
Integer d = -1;
if (trimmedPhone.length() > 0 && !(trimmedPhone.startsWith('+'))) {
Integer e = 0;
String cleanPhone = '';
if (trimmedPhone.startsWith('1'))
trimmedPhone = trimmedPhone.subString(1, trimmedPhone.length());
Integer i = 0;
List < String > b = trimmedPhone.split('');
for (; i < b.size(); i++) {
String f = b[i];
Integer theNumber = -1;
if (stringNumberToIntegerMap.containsKey(f)) {
theNumber = stringNumberToIntegerMap.get(f);
if (theNumber >= 0 && theNumber <= 9) {
if (e == 0) c.add('(');
else if (e == 3) c.add(') ');
else if (e == 6) c.add('-');
c.add(String.valueOf(theNumber));
e++;
}
}
if (!(theNumber >= 0 && theNumber <= 9) && f != ' ' && f != '-' && f != '.' && f != '(' && f != ')' && f != '') {
d = i;
break;
}
}
if (d >= 0) {
c.add(' ');
List < String > tempList = new List < String > ();
for (Integer j = d; j < b.size(); ++j) {
tempList.add(b[j]);
}
c.addAll(tempList);
}
if (e == 10 && c.size() <= 40) {
formattedNumber = '';
for (String a: c) {
formattedNumber += a;
}
}
}
return formattedNumber;
}
}
I could have probably used Regular Expression which might have reduced number of script statements. But since salesforce has no more limit on the number of script statements per execution I think this is a good solution and it has been working fine in the org where it is processing 200 phone numbers at a time in a batch of 200 orders. I call this apex method on the before insert trigger.
@isTest
public class PhoneFormatterTest {
static testMethod void testFormatPhone_Basic() {
String phoneNumber = '5555555555';
Test.startTest();
String formatterNumber = PhoneFormatter.formatPhone(phoneNumber);
Test.stopTest();
System.assertEquals('(555) 555-5555', formatterNumber, 'Phone number should have been correctly formatted');
}
static testMethod void testFormatPhone_Complex() {
String phoneNumber = '5555555555ext 23';
Test.startTest();
String formatterNumber = PhoneFormatter.formatPhone(phoneNumber);
Test.stopTest();
System.assertEquals('(555) 555-5555 ext 23', formatterNumber, 'Phone number should have been correctly formatted');
}
static testMethod void testFormatPhone_Complex_Strip1() {
String phoneNumber = '15555555555ext 23';
Test.startTest();
String formatterNumber = PhoneFormatter.formatPhone(phoneNumber);
Test.stopTest();
System.assertEquals('(555) 555-5555 ext 23', formatterNumber, 'Phone number should have been correctly formatted');
}
}
I hope you find it useful.
Useful info
ReplyDeleteHi basu,
ReplyDeleteThis is great information and exactly what I was looking for. I was just about to checkout the JS that SF uses for phone formatting when I ran across this blog post. I did add a pattern matcher to check the format and if it matches then we can skip the processing.
public static final String PHONE_REGEX = '\\([4-6]{1}[0-9]{2}\\) [0-9]{3}\\-[0-9]{4}$';
public static Pattern US_PHONE_PATTERN = Pattern.compile(PHONE_REGEX);
public static String formatPhone(String phoneNumber){
if(US_PHONE_PATTERN.matcher(phoneNumber).matches()){
System.debug('it matches!!');
return phoneNumber;
}
...
Thanks again!