Monday, December 9, 2013

Opening form from infolog "show" button with a specific record

Hi Friends,
Another small line of code, good to keep handy.
We can use info log to open a form with a specific record. You can use this while developing any custom process which create new orders in system, it does not adds any business value but definitely increases the quality and user experience.
See below the sample of how we can do this:


This can help users to open the newly created order quickly without jumping between modules and forms.
This also happens in standard AX at some places. A good example is when we create purchase orders from item requirements for a project.
 

Saturday, November 30, 2013

Picking setup in Microsoft Dynamics AX

Hi Friends,
In this post I want to highlight how Microsoft Dynamics AX determines the picking method for an order line by taking the example of sales line. This setup is important for companies having major focus on supply chain.

When posting picking list of a sales order, you can view the type of picking determined by the system for a sales line on the lines details tab on the post picking list form as shown below:


If the check box is not checked then system processes the line as an order picking.
User can change the value by checking/unchecking the check box before posting which is a great example of flexibility provided by Microsoft Dynamics AX.

So now let us see how system determines the picking method for a line. The setup can be done on three places, the sequence in which system checks is as following:

1. First place where system checks the picking method is the "Use consolidated picking method" field on the warehouse item setup defined for the item:


 
If the value defined here is "Yes" then system considers the line for consolidated picking. If the value is "No" then system considers the line for order picking. If the value defined is "According to warehouse setup" then system continues to check the second level of setup.

2. If the setup on warehouse items is "According to warehouse setup" then system checks the picking method defined on warehouse used in sales line:


If the value defined here is "Yes" then system considers the line for consolidated picking. If the value is "No" then system considers the line for order picking.If the value defined is "According to model group" then system continues to check the third level of setup.

3. If the picking method defined on warehouse of "According to model group" then system checks the value of field "Consolidated picking method" on the model group defined on item:




The code to read the above setup can be found at useWMSOrder() method written on salesLine table. See below the sequence of methods called to determine the picking method.
The code really simple to read and a good example where reading code is easier then jumping on different forms to understand the setup :)



An example of this method call is on initFromSalesLine method when creating the salesParmLine as shown below:




Thanks for reading the blog. Keep sharing and take care.

Monday, November 25, 2013

AX2012 : 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 it is good practise to make sure that there are no compilation errors in the code.
 

Friday, November 22, 2013

AX2012:Restore or (Ctrl + F5) command on forms using X++ code

Hi Friends,
This is a simple tip but good to keep the information handy.
When the records displayed on the form are updated by some other process we get an error "The values displayed in the form are not current, so an update or deletion cannot be made. To view the current values, on the Command menu, click Restore or press CTRL+F5".

In one of my recent projects, there was a situation when I wanted execute ctrl+ F5 command from code. I looked into the task macro but this command was not defined there so the challenge was to find the task id for this command so that I can pass it in element.task() method.

In order to get this task ID, I override the task method on the form and enabled debugger, opened the form and pressed ctrl + F5. The method was called and I got the task ID as 2839.

So in order to execute ctrl+F5 just call element.task(2839) and the record values will be restored.

You can also find task ID of other commands using this approach.

Thanks for reading the blog.
Keep sharing.

Tuesday, November 5, 2013

AX2012 R2 CU7 released - Summary of few technical enhancements

Microsoft  announced the release of Cumulative Update (CU) 7 for Microsoft Dynamics AX2012 R2 on 1st Nov 2013.The update can be downloaded from here

While we are waiting for complete details to be out on partnersouce, we can still find out many good details on technet. The what's new link for modules, features and country specific regions on technet is here.

Below are some major technical enhancements I came across on digging technet:

  • AxBuild.exe utility program to accomplish a full X++ compile to p-code on AOS. This is much faster then the client compile. This utility start several temporary instances of the AOS and tells each AOS which piece of X++ compile to accomplish. It then consolidates results from each AOS and reports them to log files.  According to Microsoft tests this is 13 times faster than the normal client compile. Isn't this cool. It is good to see new tool to save time for partners/customers in the most time consuming technical maintenance activity. More details can be found on technet article here 
  • Backup and Recovery : With the release of CU7, Microsoft Dynamics AX2012 R2 now includes a Volume Shadow Copy Service (VSS) writer which integrates with windows VSS framework. This will be an interesting area to explore. More technical details can be found here.
  • Data export/import framework is now shipped as a part of standard Microsoft Dynamics AX instead as an add-on. A whole new set of entities are added to the portfolio. 
  • Office add ins improved performance and new feature which can be found here
  • Reporting : Cool new features to enhance working experience like new methods to set advance printer properties, power shell command to integrate multiple report server instances, new classes to improve performance on report server. More details can be found here

There is a whole new set of things to explore in Microsoft Dynamics AX, keep exploring and keep sharing.


Saturday, October 5, 2013

Be careful in while using menuFunction class to run a menu Item using X++ code

Hi Friends,
Many times while developing/customizing processes in Microsoft Dynamics AX, we are required to call forms through X++ code. Sometimes people use MenuFunction class and sometimes ClassFactory.

In case you use menu function class then be careful as recently I faced a situation where system was crashing at menuFunction.run() call. In this situation we found classFactory() to be working fine. This situation arised when AOS and Client were on different machines.

I will explain the scenario and reasons now with the below example:
  • Create a new class and a static function which always runs on a client. Inside this function we are creating an instance of MenuFunction class to run the display menu item "CustGroup"




  • Call this function from a job as shown below you will notice that form will open:

  • Change the function declaration to run it on server as shown below
  • Now let's use classFactory to run the form and again change the function declaration to run the function on client

  • Run the job and the form opens up.
  • Now change the function definition to run the function on server.

  • Run the job and the form opens up.
Reason I found is that classFactory is having run on property as "Called from" so it can be initialized either from client or from server. However in standard AX most menu items have run on property set as "Client". See below the display menu item custGroup properties:



 So if you try to instantiate menuFunction class from a code running on server to run a menu item which runs on client then your system will stop responding and ultimately crash, however classFactory runs fine in both the situations.

To summarize the scenario:
  • AOS and client are on different machines which is mostly a real time situation.
  • The called menu item has run on property set as client (Most standard AX display menu items are set this way)
  • The menu function was instantiated from code running on server side. 
  • In case menu function is instantiated from a code running on client, then it works fine.
I would suggest to prefer using classFactory rather than menuFunction class to call a form as it works always :). However please consider security implications of using classFactory.

P.S -> For testing the above scenario make sure AOS and Client are on different machines. If everything is installed in one box then this scenario can't be replicated.

Thanks for reading the blog.

Cheers!!!


Thursday, September 26, 2013

AX2012 : Post costs for a project using X++ code

In this post I would like to share X++ code to post costs for a project without any user intervention. Normally post cost  is a three step process, but before running this process you should have proper data setup in the system and have some transactions against the project:

Step 1: User open post cost screen from project form



Step 2: Click on select button the following selection criterion screen opens up














Step 3 - Post: User fills the selection criterion and click OK, system generates some records based on this selection and those records are shown in the post cost screen as shown below and then user posts the cost and these can be seen in posted transactions of the project.

 
















In this process technically system populates some temporary table buffers based on the user selection criterion and then posts the costs based on the temporary tables populated in step 2. It is important to know the classes and there hierarchy involved in this process.
Hierarchy of classes used to build the temporary table buffers for posting the cost based on user criterion are shown below:















Hierarchy of classes used to post the cost is shown below

 











The three steps shown above can be automated using the below X++ code job:

 


















Let me show you how the code relates to the actual steps:
The selection criterion in step 2 goes here:
You can create a setup to run the code on any setting. For illustration I have used Balance in the job.















The Query criterion in step 2 again goes here


 
The assignment of temporary table buffer to post the cost goes as shown below:














Trigger of post function goes here:




For those who quickly want to reuse the code, here it is:

  Args                                args;
  ProjPeriodPostingSelectCost_Proj    projPeriod;
  ProjId                              projId = strFmt("%1*",'JOB001159'); //Your project Number
  ProjPeriodPostingLedger             projPeriodPosting;

  args = new Args();
  args.parmEnumType(enumNum(ProjCostSales));
  args.parmEnum(ProjCostSales::Cost);
  projPeriod  = ProjPeriodPostingSelect::newProj(args,projId);
  projPeriod.setQueryRange();
  projPeriod.initQuery();
  projPeriod.parmProjLedgerStatus(ProjGroup::periodic2ledgerStatus(ProjLedgerStatusPeriodic::BalanceSheet));
  projPeriod.parmTransActionDate(systemDateGet());
  projPeriod.parmQueryCost(NoYes::Yes);
  projPeriod.parmQueryEmpl(NoYes::Yes);
  projPeriod.parmQueryItem(NoYes::Yes);
  projPeriod.parmProjTimeMaterial(NoYes::Yes);
  projPeriod.parmProjInternal(NoYes::Yes);
  projPeriod.createTrans();

  //Posting the cost
  projPeriodPosting  = ProjPeriodPostingLedger::construct(args);
  projPeriodPosting.getLast();
  projPeriodPosting.parmProjLedgerStatus(ProjLedgerStatus::BalanceSheet);
  projPeriodPosting.parmtransActionDate(systemDateGet());
  projPeriodPosting.parmAcknowledgementDate(systemDateGet());
  projPeriodPosting.parmTmpProjPeriodic(projPeriod.tmpProjPeriodic());
  projPeriodPosting.parmTmpProjPeriodicCost(projPeriod.tmpProjPeriodicCost());
  projPeriodPosting.parmTmpProjPeriodicSale(projPeriod.tmpProjPeriodicSale());
  projPeriodPosting.run();

Next section is for those interested in deep diving into the job:

U might notice that I have declared object of ProjPeriodPostingSelectCost_Proj class instead of ProjPeriodPostingSelectCost and the reason for this is I need to initialize query for the project. If you debug the standard AX class then you will notice that the function to initialize it for a project is called from the dialog() method of class "ProjPeriodPostingSelectCost_Proj "

 





















If you dive into this function you will notice that the query is getting initialized here

















As we are doing this fully behind the scenes and will not be calling the prompt() method so we cannot initialize the query from the base class as it does not has this function






















So in order to initialize our query properly we need to call this method.Another important thing to note is the sequence of calling the methods as shown in job is important.

Thanks for reading the blog. Have a great day!!!
Rachit Garg

Wednesday, September 25, 2013

AX2012 : Custom lookup on Dialog control - A standard AX 2012 example


Recently while debugging a process of approving BOM, I came across a standard AX example where registerOverrideMethod() is used to create lookup on a dialog field. Thought to share with the community.

 

There are some nice blogs which explain more about this method :




 
Apart from having the flexibility to create custom lookups on dialog, this also helps us to reuse the existing code.

Saturday, June 29, 2013

VT-x features locked error resolution while setting AX2012 R2 VPC on Windows 8-64 bit machine.

Hi Friends,

I want to share this experience, recently I was configuring AX2012 R2 VPC which I downloaded from Microsoft information source, on my new HP machine having  Windows 8 64 bit operating system and Intel(R) Core(TM) i7-3630QM CPU @ 2.40 GHz processor.

I was configuring it in an Oracle VM virtual box using Oracle VM Virtual Box Manager.

I found some really good blogs having detailed description of how to do it :

http://www.doens.be/2011/11/how-to-run-a-microsoft-ax-2012-hyper-v-on-virtualbox/

http://dynamicsnavax.blogspot.in/2011/04/how-to-run-ax2012-hyperv-on-virtualbox.html

http://axretail.blogspot.in/2012/08/ax-retail-2012-vpc-configuration-on.html


So I followed them and once the setup was completed, I started the virtual machine. To my surprise I got the below error message on starting it :
"VT-x features locked or unavailable in MSR.(VERR_VMX_MSR_LOCKED_OR_DISABLED)"


So I again checked my setup and made sure that Hardware Virtualization is enabled in my VM settings, it was enabled but still I was getting the error.




So I started searching for the solution in various forums, I even went to Intel forums to read more about hardware virtualization. Fortunately I came across one of the forum mentioning that by default hardware virtualization is disabled in BIOS settings of most of Intel processor laptops by vendors for better performance and in order to enable it we need to go to host machine BIOS and turn on the virtualization technology.

Keeping my fingers crossed I restarted the machine, jumped into the BIOS of the machine and under system configuration group I found virtualization technology option. It was actually disabled, I turned it on then then saved the settings and exited from the BIOS. I also captured the screen through my mobile camera.



Now when I ran the AX virtual machine, it started up smoothly. Never thought that to start a VM we might need to change BIOS settings.

P.S --> The above information is based on my experience and in case you are getting the same issue that please change BIOS on your own risk or contact your vendor technical support team.