Visualize DocuRef notes in grid

With Dynamics AX you can attach document references like Word files, Excel sheets, mail, fax and notes to any displayed record. The icon to do so can be found in the forms toolbar. Unfortunately it’s hard to discover if a document is attached to a record. Therefore it’s helpful to display an icon in the overview grid to indicate attached documents.

document references

Create a new Integer extended data type called DocuRefIcon and label it with Documents (@SYS124737). Set the help text to Document Handling (@SYS22623).

Add a display method showDocuRefIcon() to the CustTable. Document references use a RefTableId and RefRecId to reference any record in Dynamics. If there is a document reference for the current CustTable record return resource id 3028 otherwise return id 0.

//BP deviation documented
display DocuRefIcon showDocuRefIcon()
{;
    if(DocuRef::exist(this.dataAreaId,this.TableId,this.RecId))
        return 3028;
 
    return 0;
}

Open the CustTable form and a new icon to the Overview grid. Set width and height properties to 16. Set CustTable as datasource and showDocuRefIcon as data method. Save and open the form. Attach a document reference to a customer and you’ll see a notes icon in the new grid column.

document handling icon in custtable grid

Extend miscellaneous charges with a site relation

Miscellaneous charges are used in Dynamics AX  to add charges to a sales or purchase order, like freight charges. Dynamics AX provides a framework to add charges per header or line. A miscellaneous charge can be defined for contact- and item relations. A relation can be defined by using a record or group. Sometimes a third relation is needed, like a site relation.  

  • Create a new enum that extends TableGroupAll called MarkupSiteCode
  • Create a new string EDT called SiteRelation
  • Add both to the MarkupAutoTable
  • Add a new relation on the MarkupAutoTable to InventSite table
    MarkupAutoTable.MarkupSiteCode == 0 (relation type: field fixed)
    MarkupAutoTable.SiteRelation == InventSite.SiteId
  • Add a new relation on the MarkupAutoTable to MarkupGroup table
    0 == MarkupGroup.Module (relation type: related field is fixed)
    MarkupAutoTable.MarkupSiteCode == 1
    MarkupAutoTable.SiteRelation == MarkupGroup.GroupId
  • Show both fields in the Overview grid at MarkupAutoSetup form
Miscellaneous Charges form

Misc. Charges form called from Accounts Receivable

  • Extend the MarkupInventCustVend enum with another element called site
  • Duplicate the MarkupGroup_Invent display menu item
    Change the name to MarkupGroup_Site and the EnumParameter to Site
  • Add the new display menu item to Accounts Receivable \ Setup \ Misc Charges
  • Add the new display menu item to Accounts Payable \ Setup \ Misc Charges
  • Populate the Site Groups with data, eg. East and West
  • Add a new MarkupGroupId field to the InventSite table
  • Add a new relation from InventSite to MarkupGroup where
    InventSite.MarkupGroup == MarkupGroup.Group and
    3 == MarkupGroup.Module (related field is fixed, where 3 is enum value Site)
  • Add the MarkupGroup field to a new Field Group and show in the InventSite form
Invent Site Markup Group

Invent Site Markup Group

Include the new site relation in the MarkupAutoTable find method.  

static MarkupAutoTable find(MarkupModuleCategory   moduleCategory,
                            MarkupModule           module,
                            TableGroupAll          accountCode,
                            CustVendRel            accountRelation,
                            TableGroupAll          itemCode,
                            ItemRelation           itemRelation,
                            TableGroupAll          siteCode = TableGroupAll::All,
                            SiteRelation           siteRelation = '',
                            MarkupReturnType       markupReturn = ReturnCodeType::None,
                            ReturnCode             returnRelation = '',
                            boolean               _forUpdate = false)
{
    MarkupAutoTable markupAutoTable;
    ;
    markupAutoTable.selectForUpdate(_forUpdate);
    select firstonly markupAutoTable
        index hint MarkupIdx
        where markupAutoTable.ModuleCategory    == moduleCategory   &&
              markupAutoTable.ModuleType        == module           &&
              markupAutoTable.AccountCode       == accountCode      &&
              markupAutoTable.AccountRelation   == accountRelation  &&
              markupAutoTable.ItemCode          == itemCode         &&
              markupAutoTable.ItemRelation      == itemRelation     &&
              markupAutoTable.SiteCode          == siteCode         &&
              markupAutoTable.SiteRelation      == siteRelation     &&
              markupAutoTable.MarkupReturn      == markupReturn     &&
              markupAutoTable.ReturnRelation    == returnRelation;

    return markupAutoTable;
}

Markups are found and created at the Markup class. Next you have to adopt the business logic there to support site and site relations. First create a new static method called siteRelation().

static SiteRelation siteRelation(TableGroupAll      siteCode,
                                 SiteRelation       site,
                                 MarkupGroupId      groupId)
{
    switch(siteCode)
    {
        case TableGroupAll::Table       :   return site;
        case TableGroupAll::GroupId     :   return groupId;
        case TableGroupAll::All         :   return '';
    }
    return '';
}

Next change the insertMarkupTrans() method. Extend the parameter declaration with an optional InventSiteId and MarkupGroupId.

server static void insertMarkupTrans(
    HeadingLine              moduleCategory,
    MarkupModule             moduleType,
    Common                   source,
    CustVendAC               account,
    MarkupGroupId            accountGroup,
    CurrencyCode             currency,
    LanguageId               languageId        = CompanyInfo::languageId(),
    ItemId                   item            = '',
    MarkupGroupId            itemGroup       = '',
    InventSiteId             site            = '', // new parameter
    MarkupGroupId            siteGroup       = '', // new parameter
    boolean                 invertSign      = false)

Declare two new variables siteRelation:SiteRelation and siteCode:TableGroupAll. Insert a third while loop on the siteCode in the second loop. Dont forget to increment the siteCode variable at the end of the loop.

while (accountCode <= TableGroupAll::All)
{
    if (moduleCategory == HeadingLine::Heading)
        itemCode = TableGroupAll::All;
    else
        itemCode = TableGroupAll::Table;
    while (itemCode <= TableGroupAll::All)
    {
        // third loop over siteCode
        while(siteCode <=TableGroupAll::All)
        {
            accountRelation=Markup::accountRelation(accountCode,account,accountGroup);
            itemRelation=Markup::itemRelation(itemCode,item,itemGroup);
            siteRelation=Markup::siteRelation(siteCode,site,siteGroup);    // new
            // ...
        } // while (SiteCode
        siteCode += 1;
    }  // while (ItemCode ....
    itemCode += 1;
}
accountCode += 1;

There are some places in Dynamics AX where Markup::insertMarkupTrans() is used. You have to modify the call so it fits the new method signature including InventSiteId and sites  MarkupGroup. Update you code at

  • SalesTable.createMarkupTrans
  • SalesLine.createMarkuTrans
  • PurchTable.createMarkupTrans
  • PurchLine.createMarkupTrans
  • PurchReqLine.createMarkupTrans
  • PurchRFQTable.createMarkupTrans
  • PurchRFQLine.createMarkupTrans
  • SalesBasket.createMarkupTrans
  • SalesBasketLine.createMarkupTrans
  • SalesQuotationLine.createMarkupTrans
  • SalesQuotationTable.createMarkupTrans
// SalesLine.crateMarkupTrans
server void createMarkupTrans(SalesTable  salesTable)
{;
    if (this.markupAllowed())
    {
        Markup::insertMarkupTrans(
                      HeadingLine::Linie,
                      ModuleInventCustVend::Cust,
                      this,
                      salesTable.CustAccount,
                      salesTable.MarkupGroup,
                      salesTable.CurrencyCode,
                      salesTable.LanguageId,
                      this.ItemId,
                      this.inventTable().salesMarkupGroup(), // new
                      this.inventDim().InventSiteId,         // new
                      InventSite::find(this.inventDim().InventSiteId).MarkupGroupId,
                      (this.LineAmount < 0));   // invert sign on creditnotes
    }
}

Connect a Windows Mobile Device with Dynamics AX

It’s easy to connect a mobile device like a smartphone with Dynamics AX using web services. This tutorial requires Microsoft Dynamics AX 2009 with AIF Webservices installed and Visual Studio for Smart Device development.

Deploy AIF Service

  1. Go to Basic → Setup → Application Integration Framework → Services
  2. Select Refresh button to update service list
  3. Enable CustCustomerService
  4. Generate the webservice

    Aif Services

    Aif Service

  5. To verify your service is working open the IIS manager
  6. Go to → Sites → Default Web Site  → MicrosoftDynamicsAxAif50  → Content View

    IIS 7 Manager on Windows Server 2008

    IIS 7 Manager on Windows Server 2008

  7. Right Click on CustomerSerivce.svc and Browser
  8. You should see a web page with a link to a WSDL file
  9. Follow the link an you should see an XML document containing the service contract

Implement Mobile Device Project

  1. Open Visual Studio and Create a new Solution
  2. Add a new Smart Device Project
  3. Go to References and add a new service reference
  4. Provide the URL of your Dynamics AX CustomerService
  5. Open Form1.cs file
  6. Add a text field (Name: textBoxAccountNum),
    a button (Name: buttonLookup)
    and a label (Name: labelName) to your form
  7. Double Click on the button and implement the service call:
private void buttonLookup_Click(object sender, EventArgs e)
{
    System.Net.NetworkCredential credentials = new System.Net.NetworkCredential();
    credentials.Domain = "YOUR_DOMAIN_NAME";
    credentials.UserName = "YOUR_USER_NAME";
    credentials.Password = "YOUR_USER_PASSWORD";

    QueryCriteria query = new QueryCriteria();
    query.CriteriaElement = new CriteriaElement[1];
    query.CriteriaElement[0] = new CriteriaElement();
    query.CriteriaElement[0].DataSourceName = "CustTable";
    query.CriteriaElement[0].FieldName = "AccountNum";
    query.CriteriaElement[0].Operator = Operator.Equal;
    query.CriteriaElement[0].Value1 = textBoxAccountNum.Text;

    CustomerService service = new CustomerService();
    service.Credentials = credentials;
    try
    {
        AxdCustomer customer = service.find(query);
        if (customer != null &&
            customer.CustTable != null &&
            customer.CustTable.Length > 0)
        {
            labelName.Text = customer.CustTable[0].Name;
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("Service Call failed",
                        "Error",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Hand,
                        MessageBoxDefaultButton.Button1);               
    }           
}

You application should look like that:

Windows Mobile 5 Emulator

Windows Mobile 5 Emulator