Friday, 10 April 2015

Importance of SaveLast() in RunBase Framework

Hi Friends,
RunBase Framework is widely used in AX. In this post, I would like to highlight the importance of SaveLast() function. Understanding of pack/unpack pattern is must to utilize this class in the most effective way.

SaveLast() is used to save the latest state of the class. That means even after the class is unpacked we can still update the packed state of the class.  



One common scenario where it is very useful is when we need to show the values of fields from the caller record on the dialog . In such scenarios this method needs to be called before the prompt() method . This way the packed state is updated with the latest values and in the dialog() method you can access the latest values. 

This can been seen in many standard AX classes which extend RunBase class





So if you are packing some variables, which you are also initialising in the main method and want to show on the dialog, then call saveLast() method before prompt() to get the most recent values.

Thanks for reading the blog. Have a great day.

Saturday, 21 February 2015

Generating QR Codes in AX 2009

Hi Friends,
Recently I worked on a task to generate and show QR code on a report in AX 2009.

In order to do this, I did the below steps:
  • Downloaded file MessagingToolkit.QRCode.dll
  • Copied it in client\bin folder

  • Added this dll file in the system references


  • Create a new display method on the report. The below code can be used to generate QR code.
display container qrcode()
{
    Bindata                 bindata = new Bindata();
    Image                   Imgobj;
    System.Drawing.Image    img;
    System.Drawing.Bitmap   obj;
    Filepath                _path;
    container               con;
    MessagingToolkit.QRCode.Codec.QRCodeEncoder encoder = new MessagingToolkit.QRCode.Codec.QRCodeEncoder();
    ;
    obj = new System.Drawing.Bitmap(encoder.Encode("TESTSTRING"));
    obj.Save(@"C:\temp\newPhoto.bmp",System.Drawing.Imaging.ImageFormat::get_Bmp());
    bindata.loadFile(@"C:\temp\newPhoto.bmp");
    con = bindata.getData();
    return con;
}


  • Add the image control on the report based on the display method. 



QR code can be seen on the report on running it.



There are many other dll files available as open source to generate QR code. Keep sharing.

Reference: I found a link to do the same on AX2012

Wednesday, 14 January 2015

AX2012 R3 : X++ code to start production order

Hi Friends,
The below X++ code can be used to start production orders in AX2012 R3 and R2 versions. I have not tested this in previous versions.





The values which we normally define on start screen can be assigned in the prodParmStartUp table buffer:


In the job I have set the automatic BOM and Route consumption as Never and have also turned off the post picking list and route card journal check boxes.

To use the code quickly here it is, the production order number and quantity are initialized in the _prodId and _qty variables:

static void prodStart(Args _args)
{
    ProdParmStartUp             prodParmStartUp;
    ProdMultiStartUp            prodMultiStartUp;
    ProdId                              _prodId = "W000034";
    Qty                                   _qty = 10000;

    ttsbegin;
    prodMultiStartUp = ProdMultiStartUp::construct(null);
    prodMultiStartUp.parmId(RunBaseMultiParm::getSysParmId());
    prodMultiStartUp.getLast();
    prodMultiStartUp.insert(ProdTable::find(_prodId), prodParmStartUp);
    if (_qty)
    {
        prodParmStartUp.StartUpQty                     = _qty;
        prodParmStartUp.PostNowBOM               = NoYes::No;
        prodParmStartUp.PostNowRoute              = NoYes::No;
        prodParmStartUp.BOMAutoConsump      = BOMAutoConsump::Never;
        prodParmStartUp.RouteAutoConsump      = RouteAutoConsump::Never;
        prodParmStartUp.update();
    }
    prodMultiStartUp.runOnServer();

    info("Done");
    ttsCommit;
}

Thanks for reading the blog. 

Saturday, 8 November 2014

X++ code to change financial dimension when assigning Inventory Site

Hi Friends,
It is good to find the out of the box available API's in Microsoft Dynamics AX, which can take the burden of writing some tricky code off your head. I recently found this API which can be used to link an existing financial dimension with the financial dimension defined on an Inventory site.

This is useful in scenarios where we create journals using X++ code and default/assign the value in inventory site field. This is a static method names changeDimension() available on InventSite table which takes the current financial dimension and the InventSiteID as inputs and returns you the merged Financial dimension. \Data Dictionary\Tables\InventSite\Methods\changeDimension()

A sample X++ code when creating an Inventory journal lines, to use this API would be something like this :
inventJournalTrans.DefaultDimension = InventSite::changeDimension(inventJournalTrans.DefaultDimension,'SITE001');

Inside this method you will find that system uses DimensionDefaultingService class to merge the dimensions.  

You will also notice in the comments that the dimension is merged only when the site link is enabled.
This means that if the financial dimension is linked to Site and the dimension link is locked then any transaction against this site can only be posted if the value of the selected dimension matches the value associated with the Site storage dimension. This setup form can be found at Inventory and Warehouse management -> Setup -> Posting -> Dimension link.
.

 
 
So if you are writing X++ code to assign inventory site to any table record which is also storing financial dimension then use the above API . This will make sure that the financial dimension value is merged properly during the creation of the record.

Thanks for reading the blog, Keep sharing.
 

Saturday, 6 September 2014

Read properties of table fields using X++ code

Hi Friends,
The below piece of X++ code can be used to read properties of table fields.
To demonstrate, the below job will check the mandatory property of the fields of a table. This comes handy during technical analysis. It can be time consuming to check the property of each field manually.

The code uses DictTable and DictField classes to iterate through the table fields and it's properties. This can also be used to check other properties of the fields of a table.


static void checkProperties(Args _args)
{
    DictTable       dictTable;
    DictField       dictField;
    int             i, cnt;
   
    dictTable = new DictTable(tableNum(CustTable));
    cnt = dictTable.fieldCnt();
    for (i= 1; i<=cnt;i++)
    {
        dictField = new DictField(tableNum(CustTable),dictTable.fieldCnt2Id(i));
        if (dictField.mandatory())
        {
            info (strFmt("Field %1 is mandatory.",dictField.label()));
        }
    }
     
}
Similar to the way we have checked the property of field using dictField object in the above job, we can also read properties of any table using the dictTable object.

These classes are used at lot of places in standard AX code to iterate through table structures. Some common scenario are when we need to show list of table/fields in lookups. 

Sunday, 10 August 2014

Using NOT LIKE in X++ select statements and query ranges

Hi Friends,
In this post I'll like to share how to use NOT LIKE operator in X++.
LIKE keyword is available in X++ but  NOT LIKE is not directly supported the way it works in SQL. It still can be achieved using X++ select statements as well as in query range values.

For illustration, I'll use an example to select all customer group records which do not start with "1" and do not start with "2", using a select statement as well as using a query object in X++.

Query Object:
If we need to write this in query range, then you need to use the power of expressions in the query range value. Visit using expressions in query ranges to get more details.
In the expression use '!1*' to define a not like condition and then separate other values  by a comma (,) as a comma will represent an AND condition in the query range expression. 


To quickly use the code, here it goes:

    CustGroup               custGroup;
    Query                   query;
    QueryBuildDataSource    qbds;
    QueryBuildRange         qbr;
    QueryRun                qr;

    query = new Query();
    qbds  = query.addDataSource(tableNum(CustGroup));
    qbr = qbds.addRange(fieldNum(custGroup,CustGroup));
    qbr.value(strFmt("%1,%2",strFmt('!%1*','1'),strFmt('!%1*','2')));

    info (qbds.toString());
    qr = new QueryRun(query);
    while (qr.next())
    {
        custGroup = qr.get(tableNum(CustGroup));
        info (custGroup.CustGroup);

    }


Select Statement:
If we need to write in select statement, then you can achieve by enclosing the like condition in brackets and then use a ! operator (! is the NOT operator in X++). Refer Keywords in X++ for details.

So if there are multiple NOT LIKE conditions which needs to be applied in a single statement, then each condition needs to be enclosed in brackets and need to have a ! operator applied as shown below.

You can see that the customer groups table has three records which starts with 1 and 2 but they are not shown in the info log.

To quickly reuse the code here it goes:

 CustGroup CustGroup;
    ;
    while select CustGroup
        where (!(CustGroup.CustGroup like '1*') && !(CustGroup.CustGroup like '2*'))
    {
        info(CustGroup.custGroup);

    }


The above code works well with AX2012 R3/R2/RTM and 2009 versions. I have not tested in any previous versions. The above information as also be found at MSDN  X++, ANSI SQL Comparison: SQL Select

Thanks for reading the blog and keep sharing.

Saturday, 28 June 2014

AX2012 R3 : X++ code to get WBS key for a project activity

Hi Friends,
I want to share a piece of code which can be used to get the value of WBS key of an activity for a project. This piece of code works well with AX2012 R3 and AX 2012 R2.
In projects module, we can define Work Breakdown Structure (WBS) for a project. A very nice integration with Microsoft Projects is already available out of the box in standard Microsoft Dynamics AX.
WBS key represents the hierarchy or level of that activity amongst all the project activities.The WBS for a project can be accessed from Projects list and details page from the "Work breakdown structure" button available under the "Plan" group of the action pane as shown below:


When you open this form, you will notice that unique WBS key is reflected against each activity. This value is dynamic, if you indend,outdent,move up, move down an activity, it will change the WBS key value. 
By dynamic value I mean it is not stored as a field in any table.So now lets explore the technical side of it.

 If you look at the form control, it is a display method coming from a method outlineNumber() written on HierarchyTreeTable.

Note this display method is not available directly on the table. If it would have been directly available on the table, then this would not have been an interesting topic to blog :). 
It is written as a display method on the form under the data-source methods as shown below:


So now we see that the display method returns the value from a function OutlineNumberFor() available on object of a class whose variable is declared with the name of controller on the form. So let's move ahead and look at the class declaration of the form, so we notice that this class is ProjWBSUpdateController



Now things get interesting, let us try to find on this form how this class is getting initialized, the best place to find this is init method of the form and you will notice the below code there:

wow...it requires so many parameters, let have a look at the new() method of this class, you will notice that only the first two parameters are mandatory and rest all have a default value assigned to them in the function definition and so are optional:



Additionally after initializing the class object the most important part is the call to updateOutlineNumbersAndPublishInPreOrder() method call. All the magic happens in this method and it makes your class object the shining star of the form ;).

So if we can get the hierarchyID and the calendarID, we can use this class to run all the business rules for us and return the key number. It is always a best practise not to reinvent the whole wheel and use the available classes out of the box.
HierarchyID --> If you try to analyse smmActivities table which stores all the project activities you will find that it is linked to HierarchyTreeTable based on it's recID and from HierarchyTreeTable you can get the hierarchyID.

CalendarID --> You can get it from the project.

So now time to knit all the above piece of code together and make is usable, so here is the job :


To quickly reuse the code here it goes:

static void wfsGetWBSForActivityNumber(Args _args)
{
    ProjWBSUpdateController         controller;
    HierarchyIdBase                         hierarchyId;
    HierarchyTreeTable                    hierarchyTreeTable;
    str                                               recordWBSId;
    smmActivities                              smmActivities;
    ProjTable                                    projTable ;
    CalendarId                                  calendarId;

    smmActivities = smmActivities::find("A000072");
    hierarchyTreeTable = hierarchyTreeTable::findRefRecId(smmActivities.RecId);
 
    calendarId = ProjTable::find(smmActivities.projId()).PSASchedCalendarId;
 
    hierarchyId = hierarchyTreeTable.HierarchyId;

    controller = new ProjWBSUpdateController(hierarchyId,calendarId);
    controller.updateOutlineNumbersAndPublishInPreOrder();
    recordWBSId = controller.outlineNumberFor(hierarchyTreeTable.ElementNumber);
    info(recordWBSId);
}

Below is the result when we run the above code for the below shown project:


Thanks for reading the blog. Have a nice day and keep sharing.