August 30, 2013

Print PDF files from AX X++ code

Print External PDF file from AX 

This job illustrates how we can print an external PDF file to a printer chosen in AX through X++ code. Here a code sample (X++ job) to do this.

static void theAxapta_pdfprint(Args _args)
    PrintJobSettings    printJobSettings = new PrintJobSettings(); 
    Dialog              dialog = new Dialog(); 
    DialogField         dialogFileName; 
    str                 adobeExe; 
    str                 adobeParm; 
    dialogFilename  = dialog.addField(typeid(FilenameOpen));

    if ( 
        adobeExe = WinAPI::findExecutable(dialogFileName.value());
        adobeParm = strFmt(' /t "%1" "%2" "%3" "%4"',

        winAPI::shellExecute(adobeExe,  adobeParm); 


Dynamics AX 2012 Certification Exams Details- Part I

Dynamics AX 2012 Certification Exams Details- Part I

Exam title Exam number
Microsoft Dynamics AX 2012 Trade and Logistics MB6-870
Microsoft Dynamics AX 2012 Financials MB6-871
Microsoft Dynamics AX 2012 Development Introduction MB6-869
Microsoft Dynamics AX 2012 Installation and Configuration MB6-872
Microsoft Dynamics AX 2012 Process Manufacturing Production and Logistics MB6-886
Microsoft Dynamics AX 2012 Lean Manufacturing MB6-884
Microsoft Dynamics AX 2012 Public Sector MB6-885
Microsoft Dynamics AX 2012 Service Management MB6-889

Error: An Unbalanced X++ TTSBEGIN/TTSCOMMIT pair has been detected... In AX

When trying to create a new record(s) in any table system shows following error
eg. At the time of creating new Sales Order and this error may appear.
Possible Reason(s):
TTS level '1' usually leaves your Ax session in an unusable state that you can't close properly.

Check all code for form or class from where this error comes and count the ttsbegin and ttscommit there must be same like if u write 2 ttsbegin u must have to write 2 ttscommit.

To resolve this error this TTS level should be ZERO, Run this job to get rid of that error, this job will find the tts level where its greater than zero and make it zero by calling TTSABORT.
static void TheAxaptaResetTTS(Args _args)
    while (appl.ttsLevel() > 0)
        info(strfmt("Level %1 aborted",appl.ttsLevel()));

Other Info:
ttsBegin: marks the beginning of a transaction. This ensures data integrity, and guarantees that all updates performed until the transaction ends (by ttsCommit or ttsAbort) are consistent (all or none).

ttsCommit: marks the successful end of a transaction. This ends and commits a transaction. MorphX guarantees that a committed transaction will be performed according to intentions.


August 03, 2013

Create Progress bars in Dynamics AX

 Create Progress bars in Dynamics AX [startlengthyoperation, SysOperationProgress,Animations ]

Progress bars are inbuilt in runbase frameworks. We can Use a progress indicator during operations that take more than 2 seconds 
Use an hourglass mouse pointer if the process takes 2-7 seconds.

Use a progress bar if the process takes 8 seconds or more.

There are many ways to display operations in progress
1) Hourglass Indicators
2) Progress Bars
3) Progress controls on the forms
4) Animate Controls

Hour Glass Indicators Example:

Use startlengthyoperation() and endlengthyoperation() between ur business logic
Example :

static void HourGlassMousePointer(Args _args)
int i;
str value;

for( i = 1; i <= 10000; i++)
value += int2str(i) + ','; // some business logic


Below is how the hourglass indicator looks

Use SysOperationProgress class to show the progress Bars
Initialize a SysOperationProgress variable.
Set a caption for the form by using the SysOperationProgress.setCaption method.
Set an animation to run while the operation is in progress by using the SysOperationProgress.setAnimation method.
A number of animations are provided with Microsoft Dynamics AX. To view them, run the Tutorial_ShowAVIFiles class. If you use one of these animation files, you need to declare the AviFiles macro at the top of your code.
Specify the total number of operation steps.
This is needed for the time-remaining calculation. If you do not set the total number of operation steps, the progress indicator is not shown. The total is often a count of the number of records, and may be time-consuming to calculate. Don't specify the total if the time is taken to calculate the records is comparable to the total time taken for the operation.

Perform the operation. For each step, specify a description and a step number.
During the execution, the progress indicator is updated accordingly. The estimated time remaining is calculated and displayed.
The default update interval is 3 seconds. If the task of updating the display takes more than 10% of the update interval due to latency on the network connection, the update interval is increased by 1 second.

Example :

static void operationProgress_progressBars(Args _args)
SysOperationProgress progress = new SysOperationProgress();
int i;


progress.setCaption("Progress bar example…");
for (i = 1; i <= 10000; i++)
progress.setText(strfmt("The value of i is %1", i));
progress.setCount(i, 1);

Below is the output:
Use progress control on the form:
Create a new progress control and change the autodeclaration property of the progress control to yes as shown in the figure.

In the init() or run() method of the form modify the code as shown below.

SysDictClass dictClass;
int i;
int classCount;
classId classId;
Dictionary dictionary;
dictionary = new Dictionary();
classCount = dictionary.classCnt();


for (i=1; i <= classCount; i++)
dictClass = new SysDictClass(dictionary.classCnt2Id(i));

Finally Animations: we can use Animations to let the end users know that process is running at the back ground.
We can use Animate controls to show the progress. Create a new form and add a animate control as shown below. Change the autoDeclaration property of the animate control to Yes

Override the run() method and paste the below code
public void run()
int i;
for (i = 1 ; i <= 10000; i ++)
Animate.animateFile(#AviPrint);; // autoplay(true);


Below is the output


Huge InventSumLogTTS table

How to fix the performance issue due to the huge InventSumLogTTS table?
When you run Master Planning, the InventSumLogTTS table enables Master Scheduling to be updated based on the changes to transactions. After Master Scheduling runs, the records in the InventSumLogTTS table are deleted. When Master planning license is present and configuration turned on, the master planning execution should clean this log periodically. But when this is seldom used, the cleanup will be less frequent contributing to the growth of the table.
If you are running master planning on a regular basis then this table will get cleaned up.


August 01, 2013

Extended Query Range in Dynamics AX

Hi Friends, 

Many developers often stuck while they try to apply range to the Dynamics AX query to filter records based on some conditions. We will try to explore the query ranges in this article and will try to play with some examples to learn how we can apply query ranges using x++ to the Dynamics AX queries.
Let’s discussed different cases...

Query q;
QueryBuildDataSource qbd;
QueryBuildRange qbr;
q = new Query();
qbd = q.addDataSource(TableNum(CustTable));
qbr = qbd.addRange(FieldNum(CustTable, AccountNum));
qbr.value('4005, 4006');

The above x++ code will generate following SQL statement.

"SELECT * FROM CustTable WHERE ((AccountNum = N'4005' OR AccountNum = N'4006'))"

qbr.value(strFmt('((AccountNum == "%1")
(AccountNum == "%2"))',

The above x++ code will generate following SQL statement.

"SELECT * FROM CustTable WHERE ((((AccountNum == "4005") || (AccountNum == "4006"))))"

Let's say we want to apply "OR" range on a DIFFERENT fields
You can use the following
 x++ code to apply the OR range to the different fields

qbr = qbd.addRange(FieldNum(CustTable, DataAreaId));
qbr.value(strFmt('((%1 == "4000")
(%2 == "The Bulb"))',
fieldStr(CustTable, AccountNum),
fieldStr(CustTable, Name)));

The above code will generate following sql statement

"SELECT * FROM CustTable WHERE ((((AccountNum == "4000") || (Name == "The Axapta"))))"

Note: We have used DataAreaId field above to apply the range however, the actual range is on AccountName and AccountNum field. This means when you use range value expressions you can use any field to obtain range object and use it to insert your range in the query. Using DataAreaId field for this purpose is the best practice.