March 07, 2013

Document handling via X++

In my previous post  Document handling In Dynamics ax, I post step by step tutorial to use base functionality of document handling. Today I Shared dirty code for document handling via X++ code.
Well, Document handling a great feature of Axapta; It really just depends on what your application requires. For instance, one application was based upon the sales order having a certain document attached to a sales order based on upon a custom enumeration.  So the button has a name like an invoice declaration for instance. 
If the button is clicked two menu options appear 
– Add document or 
- View document; 

*If the add document button is clicked
The select file dialog appears and the user selects a file and clicks OK. At this point, the file is written to the document handling table with the custom enumeration marked as “Invoice declaration”. 

*If the view document option is selected and there is a file to view, 
The standard documentation form will appear and the document will automatically be launched for viewing. 

What I decided to do is was find the lasted record with the enumeration set as the button that is being clicked. I pass RecId of this record using args to the Document handling form so when the form is launched I have access to the recId of the record I want to see. I set a class declaration variable of type Int64 to the recId of being passed in so I have access to the variable all over the form. This way I can use the variable in conditional statements to determine if I want to execute code. Below I will demonstrate how to insert a record in the document handling form and how I view a document of selection from the document handling form from the calling form.

Loading a document from the sales order to the document handling table

    Args                            args = new args();
    formrun                         FormRun;
    filenameSave                    filename;
    Args                            args1 = new args();
    wfsEMSalesOrderDocumentation    wfsEMSalesOrderDocumentation;
    docuref                         docuref;
    form                            form2;
    FilenameFilter                  _conFilter;
    filename                        file;
    recid                           docuvaluerecid;
    docuvalue                       docuvalue;
    int                             hwnd;//wfs ctodd 6/21/2012
    ;

    if(SalesTable)
    {
        _conFilter = ['All FIles','*.*'];
         hWnd = element.hWnd();
        file = WinAPI::getOpenFileName(infoLog.hWnd(),_conFilter,'','Select Document Path');
        if(file)
        {
            ttsbegin;
            docuref.TypeId = "File";
            docuref.Name   = "Commercial Invoice";
            docuref.Notes  = docuRef.Notes;
            docuRef.Restriction  = DocuRestriction::External;
            docuref.RefCompanyId = SalesTable.dataAreaId;
            docuref.WfsExportType = wfsexporttype::CommercialInv;
            docuref.RefTableId   = tablenum(SalesTable);
            docuref.RefRecId     = SalesTable.RecId;
            docuref.insert();

           docuvalue.initValue();
           docuvalue.insert();
           docuref.ValueRecId = docuvalue.RecId;
           docuref.update();
           docuvaluerecid = docuvalue.RecId;

           select forupdate docuvalue where docuvalue.recid == docuvaluerecid;
           docuvalue =  docuvalue::writeDocuValue(docuref,file);
           ttscommit;
      }

Viewing a file to the document handling table from the sales order table

     Args                            args = new args();
    formrun                         FormRun;
    filenameSave                    filename;
    Args                            args1 = new args();
    wfsEMSalesOrderDocumentation    wfsEMSalesOrderDocumentation;
    docuref                         docuref;
    form                            form2;
    FilenameFilter                  _conFilter;
    filename                        file;
    recid                           docuvaluerecid;
    docuvalue                       docuvalue;
    ;

    if(SalesTable)
    {
        args = new Args();
        args.name(formstr(docuview));
        select reverse docuRef  order by createdDateTime 
where Docuref.RefTableId == salesTable.TableId 
     && docuRef.RefRecId == salesTable.RecId 
     && docuRef.WfsExportType == wfsExportType::CommercialInv;

        args.record(docuRef);
        args.parm(int642str(docuRef.RecId));
        args.caller(this);

        FormRun = classfactory.formRunClass(args);
        FormRun.init();
        FormRun.run();
        FormRun.wait();

        salesTable_ds.reread();
        salesTable_ds.refresh();
    }


When viewing my document I want to pass in the record I want to see from the document handling form
//This is the document handling form init method

void init()
{
    #define.ctrlBuildAdd('ctrlAdd')
    DocuType                            docuType;
    FormBuildMenuButtonControl          menuCtrl;
    FormBuildFunctionButtonControl      itemButtonCtrl;

    if (! infolog.parmDocuHandlingActive())
    {
        throw(error("@SYS60737"));
    }
    if (infolog.parmDocu().isDocuViewSet())
    {
        infolog.parmDocu().setActive();
        throw Exception::Info;
    }
    optionView = new DocuOptionView();
    optionView.getLast();

    DocuType::createDefaults();
    docuTypeIdFile = DocuType::typeFile();

    menuCtrl = this.form().design().control(#ctrlBuildAdd);
    while select docuType
        index TypeIdx
    {
        itemButtonCtrl = menuCtrl.addControl(FormControlType::MenuFunctionButton,docuType.TypeId);
        itemButtonCtrl.menuItemType(MenuItemType::Action);
        itemButtonCtrl.menuItemName(menuitemactionstr(DocuActionNew));
        itemButtonCtrl.text(docuType.TypeId);
    }

//Here I set my variable exportRecId to the recId of the parameter I passed in using args
    if(element.args().caller().name() == formstr(wfsEMExportSales)) // dms
 {
 exportRecId = str2int64(element.args().parm());
 }
    super();
    link.enabled(false);
    multiPaste.enabled(false);

    formSplitter_Y = new SysFormSplitter_Y(grpSplit,grpRefGrid,this);
}

Here is the init method on the datasource DocuRef I need to create a query range

void init()
{
    Query           q;
    QueryBuildDataSource qB;
    super();

    q = new Query();
    qB = q.addDataSource(tablenum(DocuRef));
    criteriaRefCompanyId    = qB.addRange(fieldnum(DocuRef,RefCompanyId));
    criteriaRefTableId      = qB.addRange(fieldnum(DocuRef,RefTableId));
    criteriaRefRecId        = qB.addRange(fieldnum(DocuRef,RefRecId));
    criteriaCreatedBy       = qB.addRange(fieldnum(DocuRef,CreatedBy));

    I create a range for the recId of the record being passed in. This is checked with a condition
 We don't want to create the range if no value exists in exportRecId

    if(exportRecId)
 {
 recIdRange = qB.addRange(fieldnum(DocuRef,recId));
 }
    element.setRangeCreateId(optionView.parmShowAllUser());
    this.query(q);

    this.cacheAddMethod(tablemethodstr(DocuRef, isValueAttached));
}

The executeQuery of DocuRef which will perform the query execution of the form for that datasource

void executeQuery()
{
    if (element.isActualFound())
    {
        criteriaRefCompanyId.value(queryValue(actualCompanyId));
        criteriaRefTableId.value(queryValue(actualTableId));
        criteriaRefRecId.value(queryValue(actualRecId));
    }
    else
    {
        criteriaRefCompanyId.value(queryValue(naStr()));
        criteriaRefTableId.value(queryValue(naInt()));
        criteriaRefRecId.value(queryValue(naInt()));
    }

    If my variable has a value then we pass that value to the range I created in the 
 in the init method
   
 if(exportRecId)
 {
 recIdRange.value(SysQuery::value(exportRecId));
 }

    super();
}

Again I use the variable exportRecId to determine if the document should automatically
be viewed when launching from the sales order form. So basically if I have the recId
from a caller I want the document to be automatically launched

void run()
{
    element.setCaption("@SYS26830");

    filter.selection(optionView.parmShowAllUser());
    showOnlyRef.value(optionView.parmShowOnlyRef());
    showImage.value(optionView.parmShowImage());
    this.setShowRef();
    this.setShowImage();
    if(exportRecId)
 {
 showImage.value(1);
 this.setShowImage();
 }
    super();
}
-Harry


March 06, 2013

Integrating Axapta with Microsoft Outlook

Integrating Axapta with Microsoft Outlook

In Microsoft Dynamics AX 4.0, you can set up the Microsoft Office Outlook Integration to integrate contacts, tasks and appointments between Microsoft Dynamics AX and Microsoft Office Outlook.
To set up the Microsoft Office Outlook Integration to integrate contacts, tasks and appointments between Microsoft Dynamics AX and Microsoft Office Outlook, follow these steps:

1. View the e-mail account setting in Control Panel, follow these steps:

a. Click Start, click Control Panel, and then click Mail.
b. In the Mail Setup – Outlook dialog box, click E-mail Accounts.
Note If the profile is not set for the desired user, click Show profiles, change to use the correct profile, click Properties, and then click E-mail Accounts.
c. Click to select the View or change existing e-mail accounts option, and then click Next.
d. Click Change.
e. In the E-mail Accounts dialog box, note the user name in the User Name field, and then note the value in the E-mail Address field.
2. Verify that all information on the Microsoft Office Outlook tab is correct in the Employee dialog box. To do this, follow these steps:

a. Click Administration, and then click Users.
b. In the User dialog box, click a user, and then click User relations.
c. On the General tab, select the employee record that you try to integrate with the current user in Microsoft Dynamics AX in the Employee field.
d. Click Human Resources, click Employee, and then click the record that you selected in step 2c.
e. In the Employee dialog box, click the Contact information tab, and then specify the correct e-mail account information in the E-mail field. This information should match the value in the E-mail Address field in step 1e.
f. Click the Microsoft Office Outlook tab, and then view the information. You may notice that not all information is specified.
Note In this step, you must verify that the "Microsoft Office Outlook user Identification" setting matches the user name in the User Name field in step 1e. This will make sure that you can synchronize Microsoft Dynamics AX and the Outlook client on the computer.
3. Run the Use current Microsoft Office Outlook profile function to set the program to use the current Outlook profile. To do this, click Function, and then click Use current Microsoft Office Outlook profile.
4. Follow these steps to synchronize contacts, tasks and appointments between Microsoft Dynamics AX and Outlook:
a. Run the Pick contact Microsoft Office Outlook folder function.
b. Run the Pick task Microsoft Office Outlook folder function.
c. Run the Pick appointment Outlook folder function.

image
5. Click Save.
if you want to save send copy in your outlook then check the box

-Harry