Friday, November 18, 2016

Format phone number for us domestic and international

Currently in AX the telephone number fields allow you to enter anything into the phone number field. The following method shows how to take whatever the user entered and format it according to usa domestic and international formats. It also supports if the user entered an extension into the field instead of the extension field.  But if they did it would only work if they started the extension with the letter 'x'

The method assumes that you are currently located within the usa.

If you are reading this and are located outside of the us I would appreciate any feedback on the formatting of the international instances.

/// <summary>
/// Format phone number into a friendly display
/// </summary>
/// <param name="_phone">
/// Phone number to format
/// </param>
/// <returns>
/// Formatted display of phone number
/// </returns>
static public LogisticsElectronicAddressLocator FormatPhoneNumber(Phone _phone)
{
    LogisticsElectronicAddressLocator unformattedPhoneNumber, newPhoneNumber, formattedPhoneNumber;
    ListIterator iterator;
    str char;
    int phoneLength;
    Counter currentCharPos;
    Phone extension;
    Counter phonePartCounter;
    List phoneParts = new List(Types::String);
    container numbers = ['0','1','2','3','4','5','6','7','8','9']; //valid numbers of a phone number

    //split the phone number and extension (if available)
    phoneParts = strSplit(strUpr(_phone), "X");

    iterator = new ListIterator(phoneParts);

    //put the phone number and extension into 2 variables so we can apply formatting separately
    while (iterator.more())
    {
        if(phonePartCounter == 0)
        {
            //first part will contain the actual phone number
            unformattedPhoneNumber = iterator.value();
        }
        else if(phonePartCounter == 1)
        {
            //second part will contain the extension
            extension = iterator.value();
        }
        ++phonePartCounter;
        iterator.next();
    }

    //get the length of the phone number with the extension removed
    phoneLength = strlen(unformattedPhoneNumber);

    //remove all non numbers from field text
    for (currentCharPos=1; currentCharPos<=phoneLength; currentCharPos++)
    {
        char = substr(unformattedPhoneNumber,currentCharPos,1);
        if (confind(numbers,char))
        {
            newPhoneNumber = newPhoneNumber + char;
        }
    }

    //get the new length after any special chars have been removed so we know what type of phone number we are dealing with
    phoneLength = strlen(newPhoneNumber);

    //format the phone number according to length
    if(phoneLength == 10)
    {
        //local number
        formattedPhoneNumber = strFmt("(%1) %2-%3",substr(newPhoneNumber,1,3), substr(newPhoneNumber,4,3), substr(newPhoneNumber,7,4));
    }
    else if(phoneLength == 11)
    {
        //local with the +1
        formattedPhoneNumber = strFmt("+%1 (%2) %3-%4",substr(newPhoneNumber,1,1), substr(newPhoneNumber,2,3), substr(newPhoneNumber,5,3), substr(newPhoneNumber,8,4));
    }
    else if(phoneLength == 12)
    {
        //international with a country code length of 2
        formattedPhoneNumber = strFmt("+%1 %2 %3",substr(newPhoneNumber,1,2), substr(newPhoneNumber,3,4), substr(newPhoneNumber,7,6));
    }
    else if(phoneLength == 13)
    {
        //international with a country code length of 3
        formattedPhoneNumber = strFmt("+%1 %2 %3",substr(newPhoneNumber,1,3), substr(newPhoneNumber,4,4), substr(newPhoneNumber,8,6));
    }
    else if(phoneLength == 14)
    {
        //international with a country code dialed from another country
        formattedPhoneNumber = strFmt("%1-%2-%3-%4-%5",substr(newPhoneNumber,1,2), substr(newPhoneNumber,3,2), substr(newPhoneNumber,5,2), substr(newPhoneNumber,7,3), substr(newPhoneNumber,10,5));
    }
    else
    {
        //no format found so just use the phone number the user inputed
        formattedPhoneNumber = newPhoneNumber;
    }

    //add the extension back onto the newly formatted phone number
    if(extension != "")
    {
        formattedPhoneNumber = strFmt("%1 x%2", formattedPhoneNumber, extension);
    }

    return formattedPhoneNumber;
}



Some of the results are as follows:
3121234567 = (312) 123-4567
(312) 123-4567 = (312) 123-4567
1(312) 123-4567 = +1 (312) 123-4567
13121234567 = +1 (312) 123-4567
131212345678 = +13 1212 345678
131212345679 = +13 1212 345679
1312123456789 = +131 2123 456789
13121234567899 = 13-12-12-345-67899
13121234567 x2345 = +1 (312) 123-4567 x2345

Calling method dynamically through DictClass

Sometimes we need to loop through all of the parameters that have been defined within a class or you need to call a method dynamically without knowing what the method name is until you get it from another source.

The following shows how to get a method name from a table and call said method (in our case a parameter method name of type NoYesId) and get the result

This example shown below is being called within a class. If you called it outside of the class you would replace the 'this' object with the class instance name.

Example: TestClass currentTest = new TestClass() you would replace 'this' with currentTest.

validationMap.ParmName = name of method

 

    NoYesId testPass;
    DictClass dictClass;
    ExecutePermission perm;
    TableThatHasParmMethodListing validationMap;


    //allow the code to run
    perm = new ExecutePermission();
    perm.assert();

    //go through all of the require test mappings that will link up to the current class being executed
    while select * from validationMap
    {
        //class the validation parm mapping for the current record
        dictClass = new DictClass(classidget(this));
        testPass = dictClass.callObject(validationMap.ParmName, this);

//testPass variable will now have the result of the parm
    }

    //revert code access
    CodeAccessPermission::revertAssert();