Workflow Approval via Email

Business SolutionsThe Microsoft Dynamics AX workflow infrastructure empowers users to configure workflow in application modules, with a specific focus on tasks and approvals.

As one of the workflow features, email messages can be configured and sent that contain links to documents that require actions. For example, an employee enters a timesheet, and then submits it to his or her manager for approval. The manager receives an email message requesting approval. The email message contains a link to the timesheet that the user entered. One of the most common requests related to this functionality has been for the capability for the manager or approver to approve or reject from the email message itself.

In Microsoft Dynamics AX 2012 R2, this functionality can now be enabled by applying a hotfix download and then installing the Microsoft Dynamics AX Connector for Mobile Applications.

For more information, download whitepaper at
http://www.microsoft.com/en-us/download/confirmation.aspx?id=37002

Global Address Book – Validate Contact Information (phone, address, email) using regular expression

image

Table: LogisticsElectronicAddress.validateField
public boolean validateField(FieldId _fieldIdToCheck)
{
    boolean ret;

    ret = super(_fieldIdToCheck);

    switch(_fieldIdToCheck)
    {
        case fieldNum(LogisticsElectronicAddress, Locator):
                    ret = this.validateContactInfo(this.Type, this.Locator);
                    if(!ret)
                        throw error("Invalid Input. Please enter your input again");
                    break;
        default:    break;

    }

    return ret;
}
LogisticsElectronicAddress.getLogisticsPostalAddress()
private LogisticsPostalAddress getLogisticsPostalAddress()
{
    VendTable vendtable;
    CustTable custtable;
    SmmBusRelTable smmBusRelTable;
    DirPartyPostalAddressView postalAddressView;
    LogisticsPostalAddress logisticsPostalAddress;

    if(this.dataSource() && this.dataSource().formRun())
    {
        // Customer
        if(this.dataSource().formRun().dataSource("CustTable"))
        {
            custtable = this.dataSource().formRun().dataSource("CustTable").cursor();
            logisticsPostalAddress = LogisticsLocationEntity::findPostalAddress(custtable, LogisticsLocationRoleType::Business, DirUtility::getCurrentDateTime(), true);

        }

        // Vendor
        else if(this.dataSource().formRun().dataSource("VendTable"))
        {
            vendTable = this.dataSource().formRun().dataSource("VendTable").cursor();
            logisticsPostalAddress = LogisticsLocationEntity::findPostalAddress(vendtable, LogisticsLocationRoleType::Business, DirUtility::getCurrentDateTime(), true);

        }

        // Prospect
        else if(this.dataSource().formRun().dataSource("smmBusRelTable"))
        {            
            smmBusRelTable = this.dataSource().formRun().dataSource("smmBusRelTable").cursor();
            logisticsPostalAddress = LogisticsLocationEntity::findPostalAddress(smmBusRelTable, LogisticsLocationRoleType::Business, DirUtility::getCurrentDateTime(), true);            

        }

        else if(this.dataSource().formRun().dataSource("LogisticsPostalAddress"))
        {            
            logisticsPostalAddress = this.dataSource().formRun().dataSource("LogisticsPostalAddress").cursor();

        }            

    }
    return logisticsPostalAddress;
}

Table: LogisticsElectronicAddress.validateContactInfo

private boolean validateContactInfo(LogisticsElectronicAddressMethodType _type, str _msg)
{
    DirPartyTable               dirPartyTable;
    LogisticsLocation logisticsLocation;
    LogisticsPostalAddress logisticsPostalAddress;
    DirPartyLocation dirPartyLocation;
    DirPartyPostalAddressView postalAddressView;
    boolean isUS = false;
    boolean retval = false;
    InteropPermission permission;
    str phoneFaxExpression;
    str urlExpression;
    str emailExpression;
    str numExpression;
    str expression;

    System.Text.RegularExpressions.Regex re;

    if(this.Location)
    {
        logisticsLocation = LogisticsLocation::find(this.Location);
    }
    else
    {
        logisticsPostalAddress = this.getLogisticsPostalAddress();
        if(logisticsPostalAddress.Location)
        {
            logisticsLocation = LogisticsLocation::find(logisticsPostalAddress.Location);
        }
        else if(logisticsPostalAddress.CountryRegionId == "USA") // This from "Create New" Customer or Vendor
        {
            isUS = true;
        }
    }

    if(logisticsLocation.RecId)
    {
        while select firstonly dirPartyLocation where dirPartyLocation.Location == logisticsLocation.RecId
        {
            while select postalAddressView
                where postalAddressView.Party == dirPartyLocation.Party &&
                        postalAddressView.IsPrimary == NoYes::Yes
            {
                if(postalAddressView.CountryRegionId == "USA")
                    isUS = true;
                else
                    isUS = false;
            }
        }
    }

    /*
        Matches    (123) 456-7890
                    123-456-7890
                    123.456.7890
                    1234567890
    */

    phoneFaxExpression = @"^[(]{0,1}[0-9]{3}[)]{0,1}[-\s\.]{0,1}[0-9]{3}[-\s\.]{0,1}[0-9]{4}$";

    /*
    Description    Checks domain names. This validates domains based on latest specifications (RFCs 952 and 1123 dealing with hostnames and RFC 1035
    dealing with domain name system requirements) except that it only includes realistic fully-qualified domains:
        1. requires at least one subdomain
        2. allows shortest top-level domains like "ca", and "museum" as longest.
    Other validation rules:
        1. Labels/parts should be seperated by period.
        2. Each label/part has maximum of 63 characters.
        3. First and last character of label must be alphanumeric, other characters alphanumeric or hyphen.
        4. Does not check maxlength of domain which incidentally is 253 characters of text (255 binary representation).
    For a regular expression that matches ALL domains: ^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)*[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?$
    Matches    : regexlib.com | this.is.a.museum | 3com.com
    Non-Matches: notadomain-.com | helloworld.c | .oops.org
    */
    urlExpression = @"^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$";

    /*
    Description    A short and sweet email address validator. Checks that the username starts and ends with an alphanumeric character, allows a few non-repeating 'special characters' (namely -, ., _, +, &) and checks for a sensible domain name (2-6 character TLD required). Some unconventional, yet technically valid, addresses will not be matched, but this is only a simple expression 😉
    Matches    test@test.com | nerdy.one@science.museum | ready&set@go.com.au
    Non-Matches    .test.@test.com | spammer@[203.12.145.68] | bla@bla

    */

    emailExpression = @"^([0-9a-zA-Z]+[-._+&])*[0-9a-zA-Z]+@([-0-9a-zA-Z]+[.])+[a-zA-Z]{2,6}$";
    numExpression = @"^[0-9]+$";

    permission = new InteropPermission(InteropKind::ClrInterop);
    permission.assert();
    re = new System.Text.RegularExpressions.Regex(expression);

    switch(_type)
    {
        case LogisticsElectronicAddressMethodType::Phone:
        case LogisticsElectronicAddressMethodType::Fax:
                if(isUS)
                    expression = phoneFaxExpression;
                else
                    expression = numExpression;
                break;
        case LogisticsElectronicAddressMethodType::URL:
                expression = urlExpression;
                break;

        case LogisticsElectronicAddressMethodType::Email:
                expression = emailExpression;
                break;

        default:
                    retval = true;
                    break;
    }

    if(expression)
    {
        re = new System.Text.RegularExpressions.Regex(expression);
        retVal = CLRInterop::getAnyTypeForObject(re.IsMatch(_msg));
    }

    return retVal;

}