Tuesday, 21 May 2013

AX2012 R2 : X++ code to create and post Inventory Movement Journal

Below is X++ code which is good to keep handy. It can be used to create and post inventory movement journals in AX 2012 R2. I have use hard coded values for illustration purpose:


        InventJournalTable              inventJournalTable;
        InventJournalTrans              inventJournalTrans;
        InventJournalNameId             inventJournalName;
        InventDim                            inventDim;
        JournalCheckPost               journalCheckPost;

        //Below code creates journal header        
        inventJournalTable.clear();
        inventJournalName =  InventJournalName::standardJournalName(InventJournalType::Movement);
        inventJournalTable.initFromInventJournalName(InventJournalName::find(inventJournalName ));
        inventJournalTable.insert();

        //Below code creates journal lines
        inventJournalTrans.clear();
        inventJournalTrans.initFromInventJournalTable(inventJournalTable);
        inventJournalTrans.TransDate = systemDateGet();
        inventJournalTrans.ItemId = "MDJ0001";
        inventJournalTrans.initFromInventTable(InventTable::find("MDJ0001"));
        inventJournalTrans.Qty = 2500;
        inventDim.InventSiteId  = '12';
        inventDim.InventLocationId = '1201';
        inventDim.wMSLocationId = 'BULK-001';
        inventJournalTrans.InventDimId = inventDim::findOrCreate(inventDim).inventDimId;
        inventJournalTrans.insert();


        //The below code posts the journal
        journalCheckPost = InventJournalCheckPost::newPostJournal(inventJournalTable);
        journalCheckPost.run();





Friday, 22 March 2013

AX2012: X++ code to get on hand on an item

Hi Friends,
In this post I would like to share a small piece of code using which we can get oh hand values for an item. Before jumping to it I would first like to share some basic information related to on hand information.
What do we need to know when we have to calculate on hand of an item?
Let us take the below example:
A company has one site , two warehouses , each warehouse has four locations and each location has two pallets. Each pallet is having 10 Pcs of an Item "CAB001" . I have illustrated the view in the below diagram:


Now if someone ask you what is the on hand of item "CAB001" you might respond back with a question : Where, in warehouse WH001 or in WH001 - Loc001 or in WH002-Loc003-P5 ??
The person will elaborate the question again: What is on hand of item "CAB001" in Warehouse WH001-Loc 003? And then you can easily say that the on hand is 20 Pcs. So let's try to see on hand values of our sample item in some different cases:
Site S001 --> 160 Pcs
Site S001, Warehouse WH001 --> 80 Pcs
Site S001, Warehouse WH002 - Loc002 --> 20 Pcs
Site S001, Warehosue WH002 - Loc004 - P7 --> 10 Pcs

So you will notice that on hand value changes with reference to the combination of inventory dimensions i.e. InventDimID against which we need to calculate the on hand of an Item. In my previous post (understanding-inventdimid ) I have explained how an InventDimID refers to a combination of Inventory Dimensions.

So now we know that in order to calculate on hand of an item we also need to know the inventory Dimensions against which we need to calculate it.
Another thing which we need to know is what on hand value we want to calculate. If you look at on hand screen you can see that on hands are calculated with respect to various business meanings:


AX out of the box provides us with classes to calculate on hand values . We can use InventOnHand class to calculate the required on hand values, below is a sample job to calculate available physical qty of the item D0001 (as shown in above image) in site 1, WH 13:


Result and mapping shown below:



InventOnHand class has other functions as well to return different qty , sample shown below:
We can also point to inventSum table object from invnetOnHand Class as get access to other on hand
values as shown below:

 Use InventOnHand class and simplify your on hand calculations.
Thanks!!!




AX2012 : Understanding InventDimID

Hi Friends,
In this post I will describe my view of what is InventDimID and how we can use it in our solutions.

We know there are different inventory dimensions available in Microsoft Dynamics AX like Site, Warehouse, Location, Pallet, Batch number, Serial number etc. These can be active for an item based on the storage dimensions assigned on it.


Let us take an example, we have an Item "BRK6348" on which Site, Warehouse, Location, Pallet ID are active and we did an inventory transaction on this item say on Site '01', Warehouse 'Main', Location 'LOC001' and Pallet Id 'PLT001' and we want to design a table to store all these values on our custom transaction table.

A simple approach is to add fields for all the inventory dimensions in your table. Imagine if there are 10 inventory dimensions in system then we need to add 10 fields in our table and if we have 100 inventory transactions for this item on the set of these inventory dimension combination then we will storing same data in 100 records in all 10 fields. This will bloat the database size and also impact the performance of queries on this table.  A sample of such table would look like below:


Now to simplify this we create a new ID field which refers to a set of combination of these values. For example ID "10001" refers to  Site '01', Warehouse 'Main', Location 'LOC001' and Pallet Id 'PLT001'. We also create a separate table to store values of these 10 fields along with this ID field and add ID field in our transaction table. So in all 100 records we can store data in only one ID field.
We are not required to store data of 10 inventory dimensions fields 100 times, instead we just need to store value of 1 field in 100 records pointing to same combination of these inventory dimensions.  A sample of such tables with some records will look as below:


This ID in Dynamics AX is known as InventDimID and the table which stores all the combinations of inventory dimensions and there ID is InventDim:



This table plays very important role in AX. Any table which stores inventory dimensions in AX like salesLine, purchLine,inventTrans all have relation to inventDim table.




There are already functions to create and find inventDimID for a combination if inventory dimensions . Most commonly used is findOrCreate just initialize a blank instance of inventDim table object, assign all your inventory dimensions and then call this function to assign the inventDimID to your record. If a invnetDimID for the combination exists then system will return it else it'll create a new and return the inventDimId.


So if you are designing new tables in system to store inventory dimensions, then leverage this smart database architecture of AX and give your solution a smart design.



Friday, 21 December 2012

X++ code to define OR conditions in QueryBuildRange for a same field in a simple way

This blog post is show how to apply OR conditions in query ranges in a simple way on a same field in a table.

For example let's take a very simple select statement:
select * from CustGroup where custGroup.CustGroup == '10' || custGroup.Group =='20';

We can of course achieve the above by using expression in query ranges (MSDN) but as it has lot of specifications which needs to be followed (Axaptapedia)  and also in situations when we do not know how many values we want to pass in the range, the above approach can be a nightmare.

However there is a simple way also: Just add range and assign value on the same field multiple times as shown below:


Query   q;
QueryBuildDataSource    qbds;
QueryRun  qr;
QueryBuildRange qbr;
;
q = new Query();
qbds = q.addDataSource(tableNum(CustGroup));
qbr = qbds.addRange(fieldNum(CustGroup,CustGroup));
qbr.value(queryValue('10'));
 
qbr = qbds.addRange(fieldNum(CustGroup,CustGroup));
qbr.value(queryValue('20'));
 
info(qbds.toString());

 The resultant select statement can be seen in below image.






Well, there are some points to remember when taking the above approach:

1. Add range on the field every time you want to have a new value in OR condition. If you apply the range only once and assign the value multiple times then system will pick the value which is assigned in the last statement something like the below image:




2. You can use the same queryBuildRange variable to assign the range multiple times. Even if you use different queryBuildRange variables system will apply it correctly. It also works without a queryBuildRange variable, you can directly apply range on QueryBuildDataSource object (this is shown in the last image).








The above code is useful in situations which I talked earlier, when you are getting the range values at run time from some list,map or may be another query. We can add ranges on the same field inside a while loop which creates the corresponding OR conditions in the resulting select statement, a sample of such code is shown below where I created a list having the customer group values on which I want to assign in the OR condition.



Thanks!!!





Wednesday, 1 August 2012

AX2012: X++ Code to verify active inventory dimensions on an item


Recently I came across a situation where I needed to validate if the inventory dimension "PalletId" is active on an item or not. After a little digging here and there, came across this piece of standard AX code to identify if an inventory dimension is active or not. It is always good to re-use standard AX code instead of writing our own logic. This helps in maintaining the quality of the code.


   InventTable     inventTable;
   InventDimParm   inventDimParm;
   ;
   inventTable   = InventTable::find('1000');
   inventDimParm =  InventDimParm::activeDimFlag(InventDimGroupSetup::newInventTable(inventTable));
   if(inventDimParm.WMSPalletIdFlag)
   {
       info("Pallet Enabled");
   }

Similarly we can validate other inventory dimensions as well.


Thursday, 14 June 2012

AX2012 : X++ code to access marked records on a form

In AX2012 there is a default mark check-box on forms showing data in grid, which allows user to mark some/all records. There are situations where we need to identify which records are marked by user and do some processing on them.

This is a short post to show how to access marked records on a form in AX2012.

I have created a button on "Production order" form, which shows the marked records when it is clicked. In order to do this, we need to:
1. Add a new button on the form.
2. Set property "MultiSelect" to Yes.
3. Override the clicked method of the button and code as shown below :




Inside the for loop you can write the logic which you want to process.




Tuesday, 12 June 2012

Use edit method to mark/unmark all records

In continuation to my previous post (Edit method - I), I'll now use edit methods to mark all and unmark all the records of a form. It is a very common requirement to have such ability on forms.
In this post we'll use the edit method created in previous post (Edit method - I) and continue to create new buttons on customer details form to mark all and unmark all records.

To achieve this,we'll be doing the following:
1. Create new buttons on customer details form to mark all and unmark all records.
2. Create new functions on customer details form to mark all and unmark all records.

Let's start:

1. Create 2 new buttons on the customer table form, and change their text property to "Mark All" and "Unmark All" respectively. The CustTable form design should look as shown below:

2. Now we create a new function on this form to mark all the records. Let's name this function as PAMarkAll. We traversed through all the records one by one using a while loop and called the edit method for each record to mark it. The code should look like:

In the above code, we have declared a variable of type custTable which will help us to traverse through all the records shown on the form.
Next we initialize it with the first record using
          custTable_ds.getFirst() function.
Then we start the while loop.
Please note the way we have called the edit method. The first parameter of the edit method signifies that the value is changed, the second parameter is the custTable variable which we are using to iterate the records on the form, the third parameter is to signify that value returned  from the edit method needs to be turned on.
After marking the currently selected record we will get the next record using
        custTable_ds.getNext() method.
The above loop will be executed till the next record is found.
At last we used element.redraw() method to redraw the form.

3. In the similar way we create a new function to unmark all the records, the only change is that we need to pass false as the third parameter in the edit method call. The function to unmark all the records should look as below:



4. The functions that we created above should be called when we click the mark all and unmark all buttons. To do this we override the clicked method of both the buttons. The clicked methods should look like:




Now that we are done with the modifications required to mark all/unmark all the records, let's open the customer master form and then play with mark all and unmark all buttons. On clicking mark all button we'll notice that all the records are marked.



On clicking Unmark all button we notice that all the records are unmarked.


So in the post we saw a good example where we can use edit methods in real time situations. In my coming posts, I'll show how we can use combination of edit and display method to achieve some good features to enhance user experience on Dynamics Ax forms.