X++ code to Count Records in Query

Following code illustrates how we can use SysQuery::countTotal() method to get the number of records in Query.

static void Query_cntRecords(Args _args)
{
    Query                query = new Query();
    QueryRun             queryRun;
    QueryBuildDataSource qbd;
    ;
   
    qbd = query.addDataSource(tablenum(CustTable));
    queryRun = new QueryRun(query);
   
    info(strfmt("Total Records in Query %1",SysQuery::countTotal(queryRun)));
   
}

X++ code to Create Cue in DAX 2009

RoleCente's main purpose is to show various data on homepage which user will get to see all at a glance . Cue is also one among them .
Basically Cues in DAX 2009 are used for visual representation of data . In Technical terms Output of Query is represented graphically.

How Cue Works 
1. Open PurchTable form , click on advanced filter (Ctrl + F3)
2. Give any criteria ( status == Invoiced) and click on modify -->Save as Cue
 3. Save the Cue by assigning Cue Id as "Total_POInvoiced" , Security profile(who all can use)

4. Created Cue can be viewed in Basic-->Setup->RoleCenter->Edit Cues.



5. In order to deploy , Edit Role center homepage
             a. Click on Add new webPart and select Cues Web Part.
             b. Click on modify webpart and select above created Cue "Total_POInvoiced" in    
                 property      sheet .
             c. Click on Apply and Ok .
             d. When you exit edit mode , you will see total number of pending Invoices as image .

6. If you click on Cue "Total Invoiced PO " on Rolecenter you will be navigated to form which will show only invoiced purchase orders.

Technically :
When you create Cue , record gets created in CuesQuery Table with Formname , menuItemName and Query created from user criterias.
So when user click on Cue , It will take you to Form from where you created Cue by using the value from menuItemname.

Following X++ Job Creates Cue for customer form.

static void DEV_createCue(Args _args)
{
    CuesQuery       cuesQuery;
    Query           query = new Query(querystr(Cust));
    ;

    cuesQuery.clear();

    cuesQuery.CueId         = "TST_CustQuery2";
    cuesQuery.Caption       = "Cue test for CustTable";
    cuesQuery.CueVersion    = 1;
    cuesQuery.CreatorUserId = curUserid();
    cuesQuery.FormName      = "CustTable";
    cuesQuery.DataSourceName = "CustTable";
    cuesQuery.Query = query.pack();
    cuesQuery.ClientMenuItemName = "CustTable";
    cuesQuery.CueMin = 1;
    cuesQuery.CueMax = 10;
    cuesQuery.Threshold = 0;
    cuesQuery.ThresholdCriteria = CuesThresholdCriteria::None;
    cuesQuery.SecurityAccessFlag = CuesSecurityFlag::SpecifiedProfiles;
    cuesQuery.AdditionalValFunc = CuesAdditionalValFunc::None;
    cuesQuery.AdditionalValField = " ";
    cuesQuery.AdditionalValTable = " ";

    if (cuesQuery.validateWrite())
    {
        cuesQuery.insert();
        info(strfmt("Cue %1 Created with SecurityRights as %2",cuesQuery.CueId,cuesQuery.SecurityAccessFlag));
    }
}

Cool....

How to Create new Role Center in DAX 2009

Role center is  EnterPrise Portal Page which is used to show data , reports, pending activities and awaiting actions as per user role in the company.
Means whenever ax starts User will get homepage where he will see the data as per his role in the organization and can be personalized further to suit his requirements.
In order to have this feature available one should install and configure EP on his/her machine/server.
 After Installation do following steps,
  1.  Once you done with RoleCenter and EP installation ,
  2.  Go to Basic->Setup->RoleCenter-->Initialize Role Center will get some default profiles 
  3.  Admin-->Setup->User Profiles , click button Import and select from AOT
  4.  Default profiles (Role Centers) will be imported and You can start using by adding your userid to that select profile.
  5. Restart the AX Client and wait till default Home Page get load.

In Order to Create New RoleCenter in DAX 2009 , Have a look in following snap..

As shown in the figure, nodes under Develop the content are different components that are used to represent various data like SSRS Report , OLAP Cube for Data in BarChart etc.                      
It doesn't mean that all these are mandatory steps while creating new role center. For testing purpose just make use of Cue as specified in below image.

  Enjoy with your new role center !!!!!!!

View Embedded Resources in Ax

In DAX 2009 we have provision to view the existing resources like icons,images that are used on User Interfaces.
System will display all the resources with their Resource Id and image type. So whenever you want to display images and don't know the id then go for embedded resources as show in following snap.

Path : Tools-->Development tools-->Embedded Resource 

How to Install DAX on Stand alone Windows XP system

Unfortunately setup of AX on the computer outside a domain is prohibited by installer. But there is a trick for doing such thing and works good.
This trick is tested under Windows XP SP2, it does not work on Vista.

For Ax 4.0 Windows XP sp2 is required , for DAX 2009 Windows XP sp3 is required.

Here are steps of the trick (borrowed from AxForum):

1. Change the value of there registry key HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\ComputerName\ActiveComputerName to any value which does not match the name of your computer
2. Set value of environment variable named "UserDnsDomain" to any other value
3. Run setup.exe
4. Restore values, changed on the steps 1, 2
5. Go to client and server setup in control panel and change computer name to the real name of your computer

In order to install EP,Workflow for DAX 2009 on Windows XP we need to install share point services on Windows XP . Please visit the below link

Install SharePoint on WindowsXP


Enjoy installing DAX .........

X++ Class to Convert WebForm to Asp.net AX User control

As you all know from Version 5.0 EP development should be done in visual studio.
this means all the existing webforms developed in version 4.0 should be converted to asp.net ax user control.
This could have been taken care during the upgrade process , but unfortunately its not.

So please download the following class to convert the webforms to asp.net ax user control. this class has been developed by MS , but i don't know how come they have missed to include the same in AOT.
Not an issue , now you can do the same by downloading the following class.


Download SysEPWebFormConverter


Note Pre-requisite :
In order to test ,please create two webform named as WebForm1 and webForm2.
When you run the class you will find the new project containing converted asp.net ax user control in the project.

Enjoyyyyy!!!!!!.

UtilElements System Table , Objects usage log table in ax .

UtilElements stores the meta-data of all the AOT objects and even this table can also be used as log for tracking creation and modification of AOT objects.
And UtilElements is not RDBMS Table , whereas it uses filesystem to store data.

AOT Path for all system tables : \AOT\System Documentation\Tables\
Can be used for ..

1. To track the object creation and modification during development. i,e When you create a new or modify existing node in AOT , like table,field,report,index etc ax kernel creates/updates records in UtilElements table .

2. Even forms/reports accessed by the end-user can be tracked .

Limitation of this log table is we can't track the deleted objects in AOT.

So if you want to track who modified what object , this is the best place to look in.

X++ Code to Export AOT Object / automatic backup of xpo's.

we need to take daily backup of our development (interms of xpo) , but we all always forget becuase of our hectic work schedules.
So use the following job and build batch application to take backup of developement in terms of xpo .
We can take aod also but the size will be more and needs to stop AOS everytime .

Following job illustrates how to export/backup all AOT Classes object.

void DEV_ExportTreeNodeExample()
{

TreeNode treeNode;
FileIoPermission perm;

#define.ExportFile(@"c:\AOTclasses.xpo")
#define.ExportMode("w")
;

perm = new FileIoPermission(#ExportFile, #ExportMode);
if (perm == null)
{
return;
}

perm.assert();

treeNode = TreeNode::findNode(@"\Classes");
if (treeNode != null)
{

// BP deviation documented.
treeNode.treeNodeExport(#ExportFile);
}

CodeAccessPermission::revertAssert();
}

Enjoy !!!!!!!!

Build your own context menu on Form field.

Context menu on field are nothing but the list of features shown when you do right click on field like filter by field,by selection ,setup etc.
Following code illustrates how you can override the standard context menu and build your own .
Best use of this is in-case of display methods where filter by field and selection are not available.
Override the standard context method available on Form fields.

public void context()
{

PopupMenu menu ;
Str filterValue;
int selectedItem;
int filter, removeFilter;
;

//super(); // Comment standard menu

menu = new PopupMenu(element.hWnd());
filter = menu.insertItem("Filter");
removeFilter= menu.insertItem("Remove Filter");

selectedItem = menu.draw();
filterValue = element.design().controlName("Table1_Usn").valueStr();

switch (selectedItem)
{
case filter :
Table1_ds.filter(fieldnum(table1,Usn),filterValue);
break;

case removeFilter :
Table1_ds.removeFilter();
break;

}
}

For illustration i have used my own objects , So please test with your own valid objects.

Remove HTML Tags from String

Following Job illustrates how to strip htmltags from string.

static void Dev_StripHTML(Args _args)
{
Str htmlSource;
;

htmlSource = "Test" +
"HTML Tags Removed ";

info(Web::stripHTML(htmlSource));


}


X++ Code to Create Purchase Order and Post the Invoice.

Following Job creates the Purchase order from code and post the invoice by making use of PurchFormLetter class.
If you don't have demo data , please test with your input values.


static void Dev_CreatePO_and_Invoice(Args _args)
{

NumberSeq numberSeq;
Purchtable Purchtable;
PurchLine PurchLine;
PurchFormLetter purchFormLetter;

;

ttsbegin;
numberSeq = NumberSeq::newGetNumFromCode(purchParameters::numRefPurchaseOrderId().NumberSequence,true);

// Initialize Purchase order values
Purchtable.initValue();
Purchtable.PurchId = numberSeq.num();
Purchtable.OrderAccount = '3000';
Purchtable.initFromVendTable();

if (!Purchtable.validateWrite())
{
throw Exception::Error;
}
Purchtable.insert();

// Initialize Purchase Line items
PurchLine.PurchId = Purchtable.PurchId;
PurchLine.ItemId = 'B-R14';
PurchLine.createLine(true, true, true, true, true, false);
ttscommit;

purchFormLetter = purchFormLetter::construct(DocumentStatus::Invoice);
purchFormLetter.update(purchtable, // Purchase record Buffer
"Inv_"+purchTable.PurchId, // Invoice Number
systemdateget()); // Transaction date


if (PurchTable::find(purchTable.PurchId).DocumentStatus == DocumentStatus::Invoice)
{
info(strfmt("Posted invoiced journal for purchase order %1",purchTable.PurchId));
}
}

Change the documentstatus to packingSlip , if you want to post packing slip.
Enjoy ....Invoicing through Code.

TextBuffer Class to replace the special characters in string.

TextBuffer class can be used to replace the text/characters in the string.
Usually its used to replace the special character with escape sequence so that string(data with special character) can be inserted into the database.

Following job illustrates how to achieve this.

static void Dev_ReplaceTxt(Args _args)
{

TextBuffer buffer = new TextBuffer();
Str message;
;

message = " hi hello's how r u's ";
message += " How r u doing's wujer's * ? ' what ur mot's anbej's";

buffer.setText(message);
buffer.replace("[*?']","\\'"); // replace special character with escape sequence
info(buffer.getText());

}

Code to Display Expiry date Message at Status Bar

Following job illustrates how you can display custom message in the status bar next to alerts. ( Mean , At bottom where you will find company,layer,currency info).

static void Dev_setStatusLineText(Args _args)
{

str msg;
;

msg = "Expiry date :"+date2str(xinfo::expireDate(),123,2,4,2,4,2);

// Force the text to be shown
xUserInfo::statusLine_CustomText(true);
infolog.writeCustomStatlineItem(msg);

}

X++ code to write data to Event viewer

Usually it will be difficult to monitor/debug Batch Jobs running on server . For e.g if something goes wrong than we can't find out why.
So we can make use of Eventviewer instead of infolog and monitor the status by checking the eventviewr .
Following Job illustrates how to write to event viewer.

static void Dev_Write2EventViewer(Args _args)
{

System.Diagnostics.EventLog eventlog;
Str logSource;
Str logName;
;

logSource = "Dynamics Ax";
logName = "Dynamics Ax Log";

// check if the log already exists
if(!System.Diagnostics.EventLog::SourceExists(logSource))
{
// create new log
System.Diagnostics.EventLog::CreateEventSource(logSource, logName);
}

eventlog = new System.Diagnostics.EventLog();
eventlog.set_Source(logSource);


eventlog.WriteEntry("Info Message");
eventlog.WriteEntry("Warning Message" , System.Diagnostics.EventLogEntryType::Warning);
eventlog.WriteEntry("Error! Please check the stack trace below. \n\n" +
con2str(xSession::xppCallStack()), System.Diagnostics.EventLogEntryType::Error);

info("Check the event viewer!");


}


Enjoy ....!!!! Batch Jobs...

How to Debugg Form Controls in Ax

As you all know X++ debugger won't work , when we place breakpoints in form controls. So we all end-up in writing the breakpoint statement in form control method.

So have a look
Debug Form Controls in Ax

Enjoy Debugging !!!!

DAX Form Tool - Get Form Details at One Place

As you all know in ax whenever we want to know form detail, always we used to do..
1. Right click on form and then click on Setup and then we get the AOT->Form path.
2. To check the datasource ,like which table its using and joined to which datasource.

I have developed tool called as Dev_FormTool which will help you to get all form details in one place.

Download
Have a look ....

Make Form/Report run automatically when dynamics Ax Starts

When ax starts Kernel Creates an instance of Info class .
Info contains StartupPost() method used to execute the code every time ax starts.

Following example opens InventTable Form automatically when you start ax.

void startupPost()
{
SysSetupFormRun formRun;
Args args = new Args();
;

args.name(formstr(InventTable));
formRun = classfactory::formRunClassOnClient(args);
formRun.init();
formRun.run();
formRun.detach();
}

So if you have any task that has to be executed every time ax start , then this is the best place to put your code.

Import Data on Startup without User Interaction.

Particularly during the test phase , its useful to import the data without user interaction.
You can do this from command line with xml file as parameter.

Steps 1 : Create an XML File as below, which specifies
a. axapta version
b. Name and Location of LogFile
c. Path of data file to be imported.



Steps 2 : Open a commandLine window and type
ax32.exe –StartupCmd=AutoRun_c:\folder\filename.XML

SysAutRun Class conatins macro for XMl Elements.
For e.g can be used for importing XPO's at startup.

AX Application Explorer in Visual Studio

Check out the new tool developed by the Developer and partner tool group of dynamics Ax for Ax style coding in visual studio.

AX Application Explorer in Visual studio





Enjoy!!!

Pre-Requisites to install Dynamics Ax 2009 and Enterprise Portal

Dynamics Ax 2009 Installation Pre-requisites.
In all cases, you must be a member of the Administrators group on the local computer where you are installing a component. The following table lists permissions that are required in addition to administrator access on the computer.



Components Required.

Connecting MSSQL DataBase with X++ Code.

As part of Customer requirements , sometimes we need to connect to DataBase otherthan Axapta DataBase. So let us explore how it can be done with X++ code.
In Ax using ODBCConnection and LoginProp its possible to connect to Database on remote server, as illustrated in the following example.I tried the following code on MSSQL Server.

static void test_ODBCConnection(Args _args)
{

LoginProperty loginProp;
ODBCConnection conn;
Resultset resultSet, resultSetCount; // get record
Statement statement1, statement2; // Create SQL Statement
ResultSetMetaData metaData ; // get Record metadate like columnname.
;

// Set Server Database
loginProp = new LoginProperty();
loginProp.setServer('SON15092');
loginProp.setDatabase('AdventureWorksDW');

// Create Connection and SQL Statement
conn = new ODBCConnection(loginProp);
statement1 = conn.createStatement();
resultSet = statement1.executeQuery("SELECT * from DimTime");

while (resultSet.next())
{
metaData = resultSet.getMetaData();
info("Column Name :"+metaData.getColumnName(1)+" Value ="+resultSet.getString(1));
}
}

Enjoy, X++!!!!!!

File Operation using WinAPI in Dynamics Ax

Finding files with WinAPI

Axapta’s WinAPI class has a bunch of static methods to handle files. The code example below shows how to utilize some of these methods to find files.

The two methods used to fetch all files matching the search criteria are findFirstFile() and findNextFile(). Don’t forget to clean up after yourself with findClose().

The code also uses three different find methods:

*
fileExists(_name) returns true, if _name is an existing file
*
folderExists(_name) returns true, if _name is an existing file or folder
*
pathExists(_name) returns true, if _name is an existing folder

The example uses the infolog for output. As with any infolog beware of performance and limitation to 10.000 lines.


static void Test_WINAPI(Args _args)
{

#File

FileName fullFileName(FileName _path, FileName _fileName)
{
FileName pathName;
FileName fileName;
FileName fileExtension;
;
[pathName,fileName,fileExtension] = fileNameSplit(_fileName);
return _path + '\\' + fileName + fileExtension;
}

void findFiles(FileName _path,
FileName _fileName,
boolean _inclSubDir = true,
FileName _prefix = fullFileName(_path,_fileName))

{

FileName fileName;
int hdl;
;
setprefix(_prefix);
if (WinAPI::folderExists(_path))
{
[hdl,fileName] = WinApi::findFirstFile(fullFileName(_path,_fileName));
while (fileName)
{
if (WinAPI::fileExists(fullFileName(_path,fileName)))
info(fileName);
fileName = WinApi::findNextFile(hdl);
}
WinApi::findClose(hdl);
if (_inclSubDir)
{
[hdl, fileName] = WinAPI::findFirstFile(_path+'\\'+#AllFiles);
while (fileName)
{
if (strlwr(fileName) != strlwr(_fileName) &&
strlwr(fileName) != strlwr('.') &&
strlwr(fileName) != strlwr('..') &&
WinAPI::pathExists(fullFileName(_path,fileName)))

findFiles(fullFileName(_path,fileName), _fileName, _inclSubDir,
fileName);


fileName = WinApi::findNextFile(hdl);

}
WinApi::findClose(hdl);

}
}
}
findFiles('c:\\Program Files','*.doc');

}

How to add "Go to main table Form" Link in Ax

Go to the Main Table Form is a feature of Dynamics AX, which allows users to jump to the main record just by right-clicking on the field and selecting the Go to the Main Table Form option. It is based on table relations and is available for those controls whose data fields have foreign key relationships with other tables.

Because of the data structure integrity, this feature works most of the time. However, when it comes to complex table relations, it does not work correctly or does not work at all. Another example of when this feature does not work automatically is when the form control is not bound to a table field. In such situations, Go to the Main Table Form has to be implemented manually.

How it works : ,
we will modify the Business relations form in the CRM module to make sure that the Employee filter at the top of the form allows users to use the Go to the Main Table Form feature from the context menu.

1. Open the smmBusRelTable form in AOT, and override jumpRef() of the EmployeeFilter control with:

public void jumpRef()
{


EmplTable emplTable;
Args args;
MenuFunction menuFunction;
;
emplTable = EmplTable::find(this.text());
if (!emplTable)
{
return;
}
args = new Args();
args.caller(element);
args.record(emplTable);
menuFunction = new MenuFunction(
menuitemdisplaystr(EmplTable),
MenuItemType::Display);
menuFunction.run(args);
}

2. To test the result, open CRM | Business Relation Details, make sure an employee number is specified in the Employee filter, and right-click on the filter control. Notice that the Go to the Main Table Form option, which will open the Employee form, is now available:

How to use Dialog in Dynamics Ax.

If you came accross a requirement , where you need to collect the information and then executes a task . In such scenario Please make use of RunBase class.
Advantage of RunBase class
1. It provides dialog for presenting and collecting the information from user.
2. Pack/Unpack methods , for storing the last value entered by the user.
3. Progress bar ,for long time process where in you can show a progress bar.
4. Validate method , to validate the data entered by the user in the dialog.

you can refer tutorial in AOT->Classes->tutorial_RunBaseForm .

How to Use Temporary Table in Form

Temporary table(Table whose property temporary set to "yes") is not persistent media , so at run-time you have to populate the temporary table and attach the same to the form/report.
For illustration purpose ,I am using inventTable data and attaching the items whose group is Parts.
Steps

1. Create temporary table as TmpTestTable with 3 fields(ItemId,Itemname,ItemGroup).
2. Create a form as TempTestTable and attach the table as datasource
3. Create a new method on the form and copy the following code

TmpTestTable populateRecords(ItemGroupId _itemGroupId)
{

TmpTestTable tmpTable;
InventTable inventTable;
;

while select inventTable
where inventTable.ItemGroupId == _itemGroupId
{
tmpTable.Itemid = inventTable.ItemId;
tmpTable.ItemName = inventTable.ItemName;
tmpTable.Itemgroup = inventTable.ItemGroupId;
tmpTable.insert();
}

return tmpTable;
}

4. Call the above method in init() after super as below
public void init()
{

super();

// Call the setTmpData method to attach records to datasource
TmpTestTable.setTmpData(element.populateRecords("Parts"));
}

X++ code to identify multiple selected records in Grid

Steps :
1. Create a new method on form and copy the following code.
2. Next create a button on form . and call the method on the button click event.
(for the button property makesure the Multiselect should be set to yes , or else by default for multiple selection system will disable the buttons)

void checkSelectedRecords()
{
InventTable inventLocal;
;
//getFirst method gets all the selected records in the grid
inventLocal = InventTable_ds.getFirst(true);

while (inventLocal)
{
info(strfmt("You selected Item %1",inventLocal.ItemId));
// get the next selected record
inventLocal = InventTable_ds.getNext();
}
}

As shown below ..

X++ code to hide content pane in ax2009

This is for developers , not for endusers.As you know it will irritate during developemnt since it is appearing on top of all windows when we open form.

static void hideContentPaneWindow(Args _args)
{

#WinApi
HWND contentPane = WinApi::findWindowEx(WinAPI::findWindowEx(infolog.hWnd(), 0, 'MDIClient', ''),0,'ContentFrame','' );
;
if (contentPane)
WinApi::ShowWindow(contentPane,#SW_HIDE); // To restore use #SW_RESTORE
}

Get AX4.0 look and feel back in Ax2009

You all might be aware that all forms in Ax2009 are behaving like independent application forms.i,e When you open any form it will get open outside the application.

So following are the two solutions to open forms in same workspace as in Ax4.0
1. Change the formdesign property windowtype(from standard to workspace).this you have to do for all the forms which is time cosuming.
2. Or else Add following line in the init method of SysSetupFormRun class.
before super() as shown in the following code

public void init()
{

//at run-time you are setting property to workspace.
this.form().design().windowType(FormWindowType::Workspace);
super();

SysSecurityFormSetup::loadSecurity(this);
this.dimensionFieldCtrls();
this.inventStorageDimFieldCtrls();

if (this.isWorkflowEnabled())
{
workflowControls = SysWorkflowFormControls::construct(this);
workflowControls.initControls();
}
}

Security Keys in Ax

Dynamics Ax provides following keys to provide the security for application

1.License Keys :
First Level Security , specifies what all featues/modules/developemnt tools we can access in the standard product.License Keys will be used after installation to unlock the product.License Keys will be issued by the microsoft for partners/vendors to develop vertical/generic solutions.

2.Configuration Keys :
Second Level Security , To Enable/Disable the object/feature for all the users.

3.Security Keys :
If you want to enable/disable object/features to group of users.

4. Record Level security :
Basically it deals with the data , if you want to restrict the viewing of records per user group than we setup record level security.