Tuesday, November 17, 2015

Hiding Dynamics AX modules for a specific role

As you may know there is an option to customize the navigation pane (which shows or hides modules), screenshots below.




From here you can hide/display multiple modules, now we can achive the same functionality from code for a specific role.

For this create a new class and within this new class 'HideAXModules' create a static method 'HideModulesForRole' and add following code within the static method,

public static void HideModulesForRole()
{
    container   cont_navButtons;
    container   cont_UserRoles;

    TreeNode            menunode;
    TreeNode            mainmenunode;
    TreeNodeIterator    menuitemiter;

    str aotName;

    int i = 1;
    int j = 1;
    int loc;

    boolean isAdmin = false;

    SecurityRole        securityRole;
    SecurityUserRole    securityUserRole;

    #AOT
    #define.Zero('0')
    #define.MainMenuLocation('\\Menus\\MainMenu')

    //Fetch all roles for currently logged in User and insert in variable cont_UserRoles.
    while select securityUserRole
        join securityRole
            where securityUserRole.User == curUserId()
                && securityRole.RecId == securityUserRole.SecurityRole
    {
        cont_UserRoles += securityRole.AotName;

        if (securityRole.AotName == '-SysAdmin-')
        {
            isAdmin = true;
        }
    }

    if (!isAdmin && conFind(cont_UserRoles, 'YourRoleName'))
    {
        mainmenunode = TreeNode::findNode(#MainMenuLocation);
        menuitemiter = mainmenunode.AOTiterator();
        menunode     = menuitemiter.next();

        while(menunode != null)
        {
            aotName = menunode.AOTname();

            if(aotName == 'Home' || aotName == 'YourMenuName')
            {
                // Prefix 1 to show module
                cont_navButtons = conIns(cont_navButtons, j, '1' + aotName);
            }

            else
            {
                // Prefix 0 to hide module
                cont_navButtons = conIns(cont_navButtons, j, '0' + aotName);
            }
            j++;

            menunode = menuitemiter.next();
        }

        // Hide Modules with 0 as prefix
        infolog.navPane().setCurrMenuButtons(cont_navButtons);
    }
}

Cheers!

Monday, November 16, 2015

Calculating sales price

To calculate sales price of an item first you need to setup few things in Retail.

1) Ensure your login is linked to one of the retail channels.

2) 1.      If you want any price or discounts to appear on the sales line then affiliation and product setup needs to be performed
a.      Affiliation: Ensure the customer is linked to an affiliation

a.      Ensure that the item is linked to a proper product category.


Now use code sample mentioned in this blog to calculate sales price of an item.

Cheers!


Thursday, September 3, 2015

Creating and retrieving document notes through AIF

Document notes are not accessible from outside AX client(EP, AIF etc) if the restriction property is set as internal, while creating document note through AIF you can specify restriction property to do this set Restriction property as "External" and set  RestrictionSpecified to True.

To set restriction on header specify these two properties,
and to set restriction on line,


Cheers!

Thursday, July 2, 2015

Invalid data container type

You might get this issue while working on web service(.NetTcp adopter) in VS or during execution of AIF document service generation wizard.

To fix this issue you have to merge the macro from the several layers so every DataContainerType of both standard AX and your custom services are mentioned.If you still see this error after merging DataContainerTypes macro do compile forward for "AfStronglyTypedDataContainer" class.

Cheers!

Monday, June 8, 2015

Reference lookup for Customer delivery address

Before writing custom lookup first you have to add reference control in your form and you have to specify some properties as shown in the screen shot below,

Now override "lookupReference" method of your reference control and add following code,

public Common lookupReference()
{
    CustTable                   custTable;
    DirPartyTable               dirPartyTable;
    DirPartyLocation            dirPartyLocation;
    LogisticsPostalAddress      logisticsPostalAddress;
    SysReferenceTableLookup     sysRefTableLookup;
    Query                       lookupQuery = new Query();
    QueryBuildDataSource        lookupQueryDataSource;

    // Construct the SysRefTableLookup object
    sysRefTableLookup = SysReferenceTableLookup::newParameters(tableNum(LogisticsPostalAddress), ReferenceGroup);

    // Add the field list that will be displayed on the lookup form
   // You can Change/Add more fields in lookup based on your requirement.

    sysRefTableLookup.addLookupfield(fieldNum(LogisticsPostalAddress, Address));
    sysRefTableLookup.addLookupfield(fieldNum(LogisticsPostalAddress, Location));

    // Construct the query's data source
    lookupQueryDataSource = lookupQuery.addDataSource(tableNum(LogisticsPostalAddress));

// To add multiple values in range.
    while select  Location from LogisticsPostalAddress
        join DirPartyLocation
        join dirPartyTable
        join custTable
            where logisticsPostalAddress.Location == dirPartyLocation.Location
                && dirPartyLocation.Party == custTable.Party
                && custTable.Party == DirPartyTable.RecId
                && custTable.AccountNum == ADCAutodesaCustomerInfo.CustAccount
    {
        // Add ranges to the query data source
        lookupQueryDataSource.addRange(fieldNum(LogisticsPostalAddress, Location)).value(queryValue(LogisticsPostalAddress.Location));
    }


    // Pass the query to the lookup object
    sysRefTableLookup.parmQuery(lookupQuery);

    return sysRefTableLookup.performFormLookup();
}

after adding this code compile your form/project to reflect the changes on form.


Cheers!

Thursday, June 4, 2015

Dynamics AX AIF Services Error: "Type 'http://schemas.microsoft.com/dynamics/2008/01/sharedtypes:AxdExtType_CFPSId_BR' is not declared."

You might get this or similar error when you activate inbound/outbound port or view document schema from data policies, To resolve this error all you need to do is
refresh AIF Services as shown below,


If you are still getting this error this means there are some errors in one or more objects related to the service you are trying to use, To get rid of this perform following steps

1) Identify objects that are causing this issue - Compile all tables that are in service query datasouce and ax* classes related to the services.
2) Fix error(s).
3) Refresh AIFservices as mentioned above.

Cheers!

Wednesday, June 3, 2015

Wildcard search in Dynamics AX



If you have to add functionality similar to wildcard like operator.

Select * from VendTable where VendTable.Name is like ‘%Vendor XYZ%’

You can use static functions SysQuery::valueLike and SysQuery::ValueLikeAfter.I used these functions in datasource ExecuteQuery() method

QueryBuildRange vendorFilter = SysQuery::findOrCreateRange(PGDFileline_q.dataSourceTable(tablenum(vendTable)),fieldNum(VendTable,AccountNum));

if (vendTxt.text()!="")
{
vendorFilter.value(SysQuery::valueLikeAfter(vendTxt.text()));
}
else
{
vendorFilter.value(SysQuery::valueUnlimited());
}

super();

Tuesday, June 2, 2015

Dynamics AX 2012: Delete operating unit

AX throws an error "This organisation participates in one or more hierarchies and cannot be deleted" when you try to delete an operating unit if it is used in one or more organizational hierarchy.

Here is a way to delete operating unit,

1) Table: OmOperatingUnit - get recid using name or name alias(this recid will be used in next three steps).

2) Table: DimensionAttributeValue -> Field: EntityInstance -> search recid in this field and delete record.

3) Table: OMHierarchyRelationship -> Field: ChildOrganisation ->  search recid in this field and delete record.

4) Table: OMOperatingUnit -> Field: recid -> search recid and delete record.

Wednesday, May 20, 2015

Importing warehouses from CSV file

Here is the code for importing warehouses from excel file,

static void InventWarehouseImportFromExcel(Args _args)
{
    SysExcelApplication   application;
    SysExcelWorkbooks   workbooks;
    SysExcelWorkbook     workbook;
    SysExcelWorksheets   worksheets;
    SysExcelWorksheet     worksheet;
    SysExcelCells              cells;
    COMVariantType        type;
    FileName                     filename;
    int                                 row =0 ;
    str                                 ProductName;
    str                 _              ProductCode;
 
    InventSiteId                 inventSiteId;
    InventLocationName   inventLocationName;
    InventLocationId         inventLocationId;
    InventLocation            inventLocation;
 
 
    application = SysExcelApplication::construct();
    workbooks = application.workbooks();
 
    //specify the file path that you want to read
    filename = "C:\\ sample path \\test.xlsx"; //add file path here.
 
    try
    {
        //  Adds the file as the first document in the collection.
        workbooks.open(filename);
    }
    catch (Exception::Error)
    {
        throw error("File cannot be opened.");
    }
 
    workbook = workbooks.item(1);
    worksheets = workbook.worksheets();
    worksheet = worksheets.itemFromNum(1);   // represents the current worksheet in my case it's (1)
    cells = worksheet.cells();
 
    // Fetches data from each cell that contains data.
    do
    {
        row++;
 
        inventSiteId = cells.item(row, 1).value().bStr();
        InventLocationId = cells.item(row, 3).value().bStr();
        InventLocationName = cells.item(row, 4).value().bStr();
 
        ttsBegin;
 
        inventLocation.InventLocationId = InventLocationId;
        inventLocation.Name = InventLocationName;
        inventLocation.InventSiteId = inventSiteId;
        inventLocation.insert();
 
        ttsCommit;
 
        type = cells.item(row+1, 1).value().variantType();
    }
    // Runs until the COMVarientType doesnot contains a data field.
    while (type != COMVariantType::VT_EMPTY);
 
    // Closes the Instance of Excel.
    application.quit();
}

Importing sites from excel file

Recently i created a job to import sites from excel file, here is the code.

    static void InventSiteImportFromExcel(Args _args)
    {
        SysExcelApplication   application;
        SysExcelWorkbooks   workbooks;
        SysExcelWorkbook     workbook;
        SysExcelWorksheets   worksheets;
        SysExcelWorksheet     worksheet;
        SysExcelCells              cells;
        COMVariantType        type;
        FileName                     filename;
        int                                 row =0 ;
        str                                 ProductName;
        str                 _              ProductCode;
 
        InventSite                    inventSite;
        InventSiteId                 inventSiteId;
        InventSiteName           inventSiteName;
ReqSitePolicy   reqSitePolicy;

        application = SysExcelApplication::construct();
        workbooks = application.workbooks();
 
        //specify the file path that you want to read
        filename = "C:\\sample path \\test.xlsx"; // add file path here.
 
        try
        {
            //  Adds the file as the first document in the collection.
            workbooks.open(filename);
        }
        catch (Exception::Error)
        {
            throw error("File cannot be opened.");
        }
 
        workbook = workbooks.item(1);
        worksheets = workbook.worksheets();
        worksheet = worksheets.itemFromNum(1);   // represents the current worksheet in my case it's (1)
        cells = worksheet.cells();
 
        // Fetches data from each cell that contains data.
        do
        {
            row++;
 
            inventSiteId = cells.item(row, 1).value().bStr();
            inventSiteName   = cells.item(row, 2).value().bStr();
 
            ttsBegin;
 
            inventSite.SiteId = inventSiteId;
            inventSite.Name = inventSiteName;
            inventSite.insert();
 
            ttsCommit;
 
            type = cells.item(row+1, 1).value().variantType();
        }
        // Runs until the COMVarientType doesnot contains a data field.
        while (type != COMVariantType::VT_EMPTY);
 
        // Closes the Instance of Excel.
        application.quit();

//site will not be visible on WHM->Setup->WH setup-> sites
       // unless you add recoelds in ReqSitePolicy table
insert_recordset reqSitePolicy (InventSiteId)
select SiteId from InventSite;
    }

Cheers!

Wednesday, May 13, 2015

Dynamics AX 2012 R2 ERD's

Here is the link for "AxErd" website that hosts entity relationship (ER) diagrams for core tables of the application modules in Microsoft Dynamics AX 2012 R2.

Monday, May 11, 2015

Cleanup User cache data (delete AUC file)

AUC means application Unicode object cache. The .auc file contains cached data for the Microsoft Dynamics AX Windows client application on the client computer.To delete AUC file
follow following step.

1. Stop AOS.
2. Delete the .auc file from users\\Appdata\ folder
3. Restart AOS.

CIL generation error : The given key was not present in the dictionary.


Recently I faced this error when generating incremental IL
"CIL generation: The given key was not present in the dictionary."

The quick way to fix this is to check the CIL log file, generally located at "C:\Program Files\Microsoft Dynamics AX\60\Server\MicrosoftDynamicsAX\bin\XppIL\Dynamics.Ax.Application.dll.log"

Here you will find the AOT object for which the CIL generator found the error. Compile that object, fix the error and then regenerate the IL.

Before generating IL make sure that there are no compilation errors in the code.

Cheers!

Duplicate type with name 'Dynamics.Ax.application.' in assembly 'Dynamics.Ax.application,

To resolve this issue perform the following steps:

  1. Full compile AX
  2. Stop the AOS
  3. Truncate the SysXPPAssembly table in SQL (the table is used to contain the assemblies and to share between multiple AOS instances)
  4. Delete the DLL and netmodule files in your AOS's bin\xppIL directory(C:\Program Files\Microsoft Dynamics AX\60\Server\MicrosoftDynamicsAX\bin\XppIL directory).
  5. Restart the AOS
  6. Perform full CIL generation

Sunday, May 10, 2015

AIF value substitution maps



By creating value substitution mapping, you can define how values are replaced when data is processed in a pipeline. Each lookup table(substitution map) can act on only one data type. For example, for the ExternalItemId data type, you can create entries that replace several part numbers with part account numbers.

Goto System administration > Setup > Services and Application Integration Framework and open Value substitution maps.





Each entry in a lookup table defines a relationship between an internal value and an external value. The way that values are substituted depends on the direction of the document transfer.

For inbound transfers, the value that you enter in the Internal value field replaces the value that you enter in the External value field.
For outbound transfers, the value that you enter in the External value field replaces the value that you enter in the Internal value field.

Cheers! :)

Thursday, May 7, 2015

How to configure automatic shutdown for all online users

Go to Menu –> Tools –> Option as shown in the screen below.




Go to General -> Interface options -> Security and specify automatic shutdown time, screen shot below.





Wednesday, May 6, 2015

Bypass validation of DocumentHash when updating a record using AIF


Here is the code to bypass validation of DocumentHash when updating a record using AIF

docVersionXml = _axInternalBase.parm_DocumentHash();

if (docVersionXml)
{
docVersionDb = document.getRecordHash();

    if (docVersionDb != docVersionXml)
    {
throw error("@SYS106156");
    }
}
else
{
throw error(strfmt("@SYS26332", AxInternalBase::stripParm(methodstr(AxInternalBase, parm_DocumentHash))));
}

Enjoy!

Force Sync AOT tables through X++


Here is the code to force the database synchronization in Dynamics Ax,

static void forceSyncDB(Args _args)
{
Dictionary dict;
int idx, lastIdx, totalTables;
TableId tableId;
Application application;
SysOperationProgress progress;
StackBase errorStack;
ErrorTxt errorTxt;

application = new Application();
dict = new Dictionary();
totalTables = dict.tableCnt();
progress = new SysOperationProgress();
progress.setTotal(totalTables);
progress.setCaption(“@SYS90206″);
errorStack = new StackBase(Types::String);
lastIdx = 0;

try
{
for (idx = lastIdx+1; idx <= totalTables; idx++)
{
tableId = dict.tableCnt2Id(idx);
progress.setText(dict.tableName(tableId));
lastIdx = idx;
application.dbSynchronize(tableId, false, true, false);
progress.incCount();
}
}
catch (Exception::Error)
{
errorTxt = strFmt("Error in table '%1' (%2)", tableId, dict.tableName(tableId));
errorStack.push(errorTxt);
retry;
}

setPrefix("@SYS86407");
errorTxt = errorStack.pop();

while (errorTxt)
{
error(errorTxt);
errorTxt = errorStack.pop();
}
}

Cheers! 

Sunday, May 3, 2015

Deploy Microsoft Dynamics AX 2012 R3 on Azure

You can deploy Microsoft Dynamics AX 2012 R3 on MS Azure virtual machines. Refer to this TechNet link for more details.

Tuesday, April 21, 2015

Debugging AIF Services in AX 2012

Regardless of the adapter type you choose, services in AX 2012 run as IL code - even if you are using the file adapter.  To debug IL code
you must use Visual Studio.
The steps for debugging a service are:
  1. On the AOS, install the AX Application Explorer from the Microsoft Dynamics AX CD by choosing the
    component Developer Tools, and then click Visual Studio Tools.  If the AX debugger is not installed,
    you will also need to install it.
  2. Open Visual Studio, create a new project, and in the AX Application Explorer find the methods in the
    service classes that are of interest.
  3. In Visual Studio add breakpoints where needed.
  4. Click Debug, and then click Attach to Process.
  5. Mark the checkboxes for Show processes from all users and Show processes in all sessions.
  6. Select AX32Serv.exe and click Attach.The Ax32Serv.exe won't be able available if you are not debugging on the AOS, so
    you need to be on the AOS.
  7. In a separate instance of VS (so have two different projects/solutions open) run the code that calls
    the service.One instance to run the code that
    calls the service and another instance of VS to do the debugging.  By
    having two instances open, you can leave the debugging instance attached to the
    AOS while you run the service code over and over again.

Tuesday, April 14, 2015

Standard Document Services 2012

You can find a complete list of standard AIF document services on TechNet.

Here is the link.  

Troubleshoot services and AIF


While looking for a solution of an issue related to AIF  I found an interesting article on TechNet for troubleshooting  AIF common issues that we face in document exchanges.I hope that will be helpful for some of you.

Here is the link.

Debugging code in AIF classes


 
There is a Piece of code in \Classes\AifOutboundProcessingService\run or \Classes\AifInboundProcessingService\run

runas(message.sourceEndpointAxUserId(),
                        classnum(AifInboundProcessingService),
                        staticmethodstr(AifInboundProcessingService, processAsUser),
                        [message.pack(), messageId]);

just comment this code and change the scope of the static method processAsUser from the same class to public and then call it exactly as below in the run method

                             AifInboundProcessingService::processAsUser([message.pack(), messageId]);

This would allow you to debug the code in Aif and the Axd's but make sure you delete these changes once you complete your debugging.


Enterprise Search in Dynamics AX 2012


Enterprise search allows MS Dynamics AX 2012 users to search for common nouns, such as 'customer' and 'cash flow report.' Users can also search for specific data, such as a customer name, product ID, telephone number, address etc. It enables users to search through data, metadata, and documents that are attached to records by using either the Microsoft Dynamics AX client or Enterprise Portal for Microsoft Dynamics AX.

Below are TechNet links to to install and configure enterprise search.

Enterprise Search

Enterprise Search configuration 


Sales Order Confirmation through code

Few days earlier i got a  requirement from client to auto confirm a sales order after creating a sales order(importing SO xml) using standard sales order document service. Here is the code for sales order conformation. 

public boolean confirmSalesOrder(SalesId _salesId)
{
     SalesFormletter SalesFormletter;
    SalesTable SalesTable;

    SalesFormletter = SalesFormletter::construct(DocumentStatus::Confirmation,true);

    SalesTable = SalesTable::find(_salesId);

    SalesFormletter.update(SalesTable,
                                              systemDateGet(),
                                              SalesUpdate::All,
                                              AccountOrder::None,
                                              false,
                                              false);

}

I Added this method in AxdSalesOrder class and called it after SO record was created in AX. 
In next few days i am going to share more information on AIF, EP and other AX stuff.