Monday, February 14, 2011

Choose to whom send what type of email from Outlook automatically in Microsoft Dynamics AX 2009

Ax 2009 came with many changes regarding addresses and contacts.

(If you want to learn more from it go here http://www.microsoft.com/downloads/en/details.aspx?FamilyID=052e9dda-667b-42bd-bd13-f8c5aa1bc0f0&displaylang=en)

Now the GAB (Global Address Book) allows you to have a centralized repository of contacts (person and/or organizations), these can be used in many different processes such as Business Relations, Leads, Sales Orders, ect.

Because of this, I came up with an idea to setup a place in the contacts table (and form) where the user can choose to whom send what type of email from Outlook automatically.
For example, in our company we send emails to the person that is asking for a quote after a Sales Quotation has been created. The same is true for a Sales Order Acknowledgement.

One of the problem that the users were experiencing was that sometimes they have 10 contacts for a Business Relationship, and when creating quotes for this business relationship, more often than not, more than one people at the customer's site wanted to get the quote. This created a lot of manual labor and many mistakes.

So I added a new tab to the smmContacts in AX2009, and within these Tab I added 5 different check boxes that represent the 5 types of emails we ussually send to customer (contacts) after an operation has been completed.

I created a new Enum named EmailTypes that has 5 elements (the same as the ones shown in the picture below).
The next picture shows the form



A contact can be assigned either one or all types of emails.

Then I created a new method in the contacts table that accepts 3 parameters as shown below:

Email contactEmail(DirPartyId partyId, EmailTypes type, QuotationId quoteId = '')//Earias
{
    Email                       email;
    ;
    //Get Email based on DirPartyId
    email = AGO_Utilities::GetContactEmailFromPartyID(partyId, type, quoteId);

    return email;
}


The above method is called from my ReportEmail class as shown below:

...
email = smmQuotationTable.contactEmail(partyId, EmailTypes::SalesQuotes, smmQuotationTable.QuotationId);
...

At the same time I created a public static method in my static class that I called AGO_Utilities where I store many common functions I use daily. This method uses the DirPartyID to find and return the Email of a contact based on the email type. If we were to have 20 users, the method will loop through all of them until it finds the correct one.


public static Email GetContactEmailFromPartyID(DirPartyId partyId, EmailTypes type, QuotationId quoteId = '')
{
    DirPartyRelationship        dirPartyRelationship;
    Boolean                     breakProcess = false;
    DirPartyId                  childPartyId;
    ContactPerson               contactPerson;
    ContactPersonId             contactPersonId;
    Email                       email = '';
    ;

    while select dirPartyRelationship where dirPartyRelationship.ParentPartyId == partyId
    {
        childPartyId = dirPartyRelationship.ChildPartyId;
        if(childPartyId)
        {
            switch(type)
            {
                case EmailTypes::SalesQuotes:
                    //Check if sales quote has a contact to it
                    contactPersonId = SalesQuotationTable::find(quoteId).ContactPersonId;
                    if(contactPersonId)
                        select * from contactPerson where contactPerson.ContactPersonId == contactPersonId;
                    else
                        breakProcess = true;
                    break;
                case EmailTypes::Invoice:
                    select * from contactPerson where contactPerson.PartyId == childPartyId &&
                               contactPerson.EmailType_Invoice == NoYes::Yes;
                    break;
                case EmailTypes::OrderAcknowledgement:
                    select * from contactPerson where contactPerson.PartyId == childPartyId &&
                               contactPerson.EmailType_OrderAcknowledgement == NoYes::Yes;
                    break;
                case EmailTypes::ShippingMarks:
                    select * from contactPerson where contactPerson.PartyId == childPartyId &&
                               contactPerson.EmailType_ShippingMarks == NoYes::Yes;
                    break;
                case EmailTypes::ARStatement:
                    select * from contactPerson where contactPerson.PartyId == childPartyId &&
                               contactPerson.EmailType_ARStatement == NoYes::Yes;
                    break;
            }

            if(contactPerson.Email || contactPerson.Email2)
            {
                if(!contactPerson.Email)
                    email =  contactPerson.Email2;
                else
                    email = contactPerson.Email;

                break;
            }

            if(breakProcess)
                break;
        }
    }


    return email;
}


After returning the email I call the SysINetMail class

mail = new SysINetMail();
mail.sendMailAttach(email, '', 'Ref.: ' + smmQuotationTable.CustomerRef+ '// '
+'@SYS5864' + '' + smmQuotationTable.QuotationId+' ', '', true, filePath+fileName, fileName);

Then I change the Quote status to "Sent"

ret = this.UpdateSalesQuotationStatus(smmQuotationTable.QuotationId);

The full method is below

boolean UpdateSalesQuotationStatus(QuotationId quotationId
{
    boolean ret = true;
    ;

    ttsbegin;
    try
    {
        select forupdate smmQuotationTable where
                         smmQuotationTable.QuotationId == quotationId &&
                         smmQuotationTable.QuotationStatus == SalesQuotationStatus::Created;

        smmQuotationTable.QuotationStatus = SalesQuotationStatus::Sent;
        if(smmQuotationTable)
        {
            smmQuotationTable.update();
            ttscommit;
        }
        else
            ttsabort;
    }
    Catch(Exception::Error)
    {
        ret = false;
        ttsabort;
    }

    return ret;
}



Then I start Outlook and the user gets an Outlook window ready to send an email.

void sendMailAttach_OLD(str     _toName,
                    str     _ccName,
                    str     _subject,
                    str     _text,
                    boolean _dialog,
                    str     _attachPath,
                    str     _attachName = "")
{


    SysInetOutlookMail outlookmail=new SysInetOutlookMail();
    outlookmail.AddRecipient(_toName);
    outlookmail.AddRecipient(_ccName);
    outlookmail.Subject(_subject);
    outlookmail.Body(_text);
    outlookmail.InsertSignature(true);
    if(_attachPath!="")
        outlookmail.AddAttachment(_attachPath,_attachName);
    if(_dialog)
        outlookmail.ShowMessage();
    else
        outlookmail.SendMail();

}

void AddRecipient(str email)
{
    ;
    if(email!="")
        _recipients.appendText(strfmt("%1;",email));
}


public str Subject(Str subject = _subject)
{
    _subject = subject;
    return _subject;
}


public str Body(str body = _body)
{
    _body = body;
    return _body;
}


public boolean InsertSignature(boolean insertSignature = _insertDefaultSignature)
{
    _insertDefaultSignature = insertSignature;
    return _insertDefaultSignature;
}


void AddAttachment(str fullFilePath,str displayName="")
{
    str newFilepath;
    container tempCont;
    ;

    if(_outlookMailAttachments==null)
        _outlookMailAttachments=_outlookMail.Attachments();

    if(fullFilePath!="" && displayName!="")
    {
             _outlookMailAttachments.Add(newFilePath);
            WinApi::deleteFile(newFilePath);
    }
    else
        _outlookMailAttachments.Add(fullFilePath);
}

No comments:

Post a Comment

Thank you for your thoughts. Your comment will appear in my blog shortly after review.

Have a great day!