How to use some of the lesser known methods of the SysQuery class

 imparted from here


When working with ranges for a query, you may have used the SysQuery class already.
With some of the methods in this blog post you can live without, but they sure can make your life as a programmer a bit easier.

Some examples. We gonna use a querybuildrange, setting it like this:

QueryBuildRange myQBR;

Now we set the actual value for the range, by using this format:


This method takes a string as argument.
But if you are not sure which type your argument is gonna be, you might wanna do a conversion to be on the safe side. It doesn't hurt to make a habit of writing your code like this:


Hey and what about that other method from the Global class, QueryValue? No use of that?
Maybe you are used to writing something like this:


This converts the argument (anytype) to a string as well. Actually, this is equally good, as this method calls SysQuery::Value().

Logical NOT

If we wanna list all the customers that do NOT have the currency EUR set up, we can do something like this:


The SysQuery class comes to the rescue here as well, by providing the exact same functionality


Check it out, this method converts the argument to a string AND adds an exclamation point in front of it.

No range value

If you range has been set up, but you don't want to apply anything yet, you can provide an empty string as argument. This way the query will retrieve all records.


Again, SysQuery has something in its toolbox for us as well:


Coming from the documentation in the code:

Used when you want to have a completely open range, no limitations; "a blank range"
use this method for future compability

Don't mix this one up with the method valueEmptyString. The methodvalueEmptyString will retrieve records with no value for the specific field.


And this one of course has an opposite, valueNotEmptyString


This will retrieve records where there is a value set up, so no null values.

To end this post, maybe the method that saves you from writing code the most: Range.
We can set ranges from/to with SysQuery class as well.


The method will add the dots ('..') when appropriate, so something like this:


Like stated at the intro of this post: Nothing lifesaving, but nice-to-haves

str2Datetime Function

str2Datetime Function:

Generates a utcdatetime value from the specified string of date and time information.
utcdatetime str2datetime( str text, int sequence ) 



The string to convert into a utcdatetime value.


A three digit number that describes the sequence of the date components in the text parameter.

A utcdatetime value that represents the specified date and time.

If the value of the sequence parameter is invalid (such as -1, or 3, or 9876), the regional settings are used to interpret the text parameter.

If the input parameters describe an invalid date/time, then an empty string is returned.

The syntax requirements for the date portion of the text parameter are flexible. The variety of valid formats is the same as in the date2str function.

Each of the following calls to str2datetime is valid and produce the same output:

utc3 = str2datetime( "1985/02/25 23:04:59" ,321 ); utc3 = str2datetime( "Feb-1985-25 11:04:59 pm" ,231 ); utc3 = str2datetime( "2 25 1985 11:04:59 pm" ,123 ); 

Each component of the date time is represented by a digit in the sequence parameter:

  • 1 – day
  • 2 – month
  • 3 – year

For example, YMD is 321. All valid values contain each of these three digits exactly one time. If the value of the sequence parameter is invalid, the regional settings are used to interpret the input text parameter.

If the input parameters describe an invalid date and time, an empty string is returned.

static void JobTestStr2datetime( Args _args ) {     utcdatetime utc3;     str sTemp;     ;     utc3 = str2datetime( "1985/02/25 23:04:59" ,321 );     sTemp = datetime2str( utc3 );     print( "sTemp == " + sTemp );     pause; }

Axapta Dialog Validation - Stack Overflow

Axapta Dialog Validation - Stack Overflow:

Here is an example in AX 2009 of how to build a simple dialog using the RunBase class. In it I create a class called DialogExample and derive from RunBase. To show the dialog you simply need to run the class, but typically this would be done by pointing a MenuItem at the class.

public class DialogExample extends RunBase {     DialogField dialogName;     Name name;      #DEFINE.CurrentVersion(1)     #LOCALMACRO.CurrentList         name     #ENDMACRO }  Object dialog() {     Dialog dialog = super();     ;      // Add a field for a name to the dialog. This will populate the field with      // any value that happens to be saved in name from previous uses of the     // dialog.     dialogName = dialog.addFieldValue(TypeId(Name), name);      return dialog; }  boolean getFromDialog() {     ;      // Retrieve the current value from the dialog.     name = dialogName.value();      return true; }  boolean validate(Object _calledFrom = null) {     boolean isValid;      isValid = super(_calledFrom);       // Perform any validation nessecary.     if (name != 'abc')     {         isValid = checkFailed('Name is not equal to abc') && isValid;     }      return isValid; }  Name parmName() {     ;      return name; }  public container pack() {     return [#CurrentVersion,#CurrentList]; }  public boolean unpack(container _packedClass) {     int version = conpeek(_packedClass, 1);      switch (version)     {         case #CurrentVersion:             [version,#CurrentList] = _packedClass;             break;         default :             return false;     }      return true; }  public static void main(Args args) {     DialogExample DialogExample;     ;      dialogExample = new dialogExample();      // Display the dialog. This only returns true if the the user clicks "Ok"      // and validation passes.     if (dialogExample.prompt())     {         // Perform any logic that needs to be run.         info(dialogExample.parmName());     } }
Typically in this scenario logic that needs to be run would be put in a run method on the class and then called into from main if the Ok button is clicked. Since the run method would be an instance method this gets rid of the need for the parm methods to access the value of the field on the dialog.

Document Handling in AX – setup and Example « Sreenath Reddy G – Dynamics AX Consultant's Blog

Document Handling in AX – setup and Example « Sreenath Reddy G – Dynamics AX Consultant's Blog

Document Handling in AX – setup and Example

Posted by Sreenath Reddy on June 18, 2007

Some initial setups for enabling document handling in AX-

On the Tools menu, select Options.
Under Document handling, select Document handling active.
Select Update toolbar line button to highlight the Document handling icon on the toolbar when you select a record with documents references.

Documents are stored in a default document archive directory and before you start creating documents, you must select the location in theParameters form.

Click Basic > Setup > Document management > Parameters.
In Archive directory, type the path to the archive directory, or use the browse button () to select a folder on your network.
Select the Number sequences tab.
In the Number sequence code list, select the number sequence to use for naming your documents.

The document management system handles several types of documents including letters, worksheets, and simple notes. Before you can create documents of a certain type, the document type must be created in the Document type form.

By default, all documents are stored in the Archive directory selected on the Parameters form. However you can select alternative folders for the individual document types.

Also by default, all document types are available from all forms, but some document types are only relevant for certain tables, such as, if you only want to create customer letters for records in the Customers form. When you associate a document type with a specific table, it is not possible to create any documents of that type, in other tables.

Create new document type

Click Basic > Setup > Document management > Document types.
Press CTRL+N to create a new document type.
In Type, type a code for the document type.
In Name, type a descriptive name for the document type.
In the Job description list, select the type of document to create.
In the Group list, select a group for the document type.

Now, I would like to explain document handling with an example for sales orders form of DOC type.

Initially set the parameters for document handling.

Go to – >Basic -> setup -> Document Management – > Parameters form

set the archive diretory path ( where the document has to be stored like c:\AxDocuments). Remember when ever u create document for a record, the document gets stored in the above location specified.

Check – use Active document table checkbox.

In the number sequences tab - select the number sequence you would like to use for the documents.

Then, If you want to enable documents for salestable – Go to – > Basic -> setup -> Document Management – > Active document tables form . Then select the name of the table here as salestable and in enable the always enabled checkBox.

Now when you open the salestable form you can find the document handling enabled on the toolbar for the salestable form. Double click the document handling icon and create a new document for that record by clicking the new button and selecting the Document menuitem button.Now you can create documents for the salestable.Once you create documents the documents will be stored in the archive path selected in the parameters form.

When ever u create a document, it hits docuref and docuvalue tables.

In the docuref,it creates a record with the tableid of the salestable, the record id of the salestable and the dataareaid ..etc..and correspondingly a record gets generated in the docuvalue with all the filenames, extensions,path etc

To view the documents in the salestable from itself, i mean in the gird itself here is the way…

Open the salestable form, Then , I would like to use icons for every record in the salestable.So i will write a display method at the salestable level.

//BP Deviation Documented
display smmDocIconNum

if ((select firstonly docuRef where
docuRef.RefCompanyId == this.DataAreaId && docuRef.RefTableId ==
this.TableId && docuRef.RefRecId == this.RecId).RecId)

return #RES_NODE_DOC;

return #RES_AM_NEW;

Now create a new window control in the gird. Add the datasource as salestable and datamethod as showDocHandIcon.

The main class where all the business logic is written is docuAction Class. Now i am going to use this class to open the documents for the records.

Now please override the Mouseup() method of the window control

public int
mouseUp(int _x, int _y, int _button, boolean _Ctrl, boolean _Shift)

int ret;
args args;

ret =
super(_x, _y, _button, _Ctrl, _Shift);

// Method at form level

return ret;

Now add showDocument() method at form level

void showDocument()
args args;
docuref docuref;

args = new args();
docuRef =



Lookups - Axaptapedia

Get it from Lookups - Axaptapedia:


Lookups are used in Axapta to show the user a list of possible values from which to select, whilst entering data into a control on a form.



Automatic lookups

Axapta has extensive support for automatic lookups, as well as the capability to manual enhance or replace the automatic system.

The standard lookup for customer accounts


The standard lookup system in Axapta is based on the use of table field or data type relations. These specify a link between a particular data type, or particular table field, and a corrsponding field in another table containing the base (reference) data.
Generally, relations are made on the datatype (EDT) in the AOT, and will then automatically apply to any table field using that EDT.
For example, in the standard application, the CustAccount EDT has a relation specified to CustTable.CustAccount. This means that any table field using the CustAccount EDT will be automatically given a lookup icon which allows the user to select from the list of accounts in CustTable.
It is possible to further restrict the values which will appear in the lookup by specifying a "Related fixed field" relations on the datatype. In this case, only those values satisfying the relation will be shown in the lookup. See the Dimension datatype for an example of this (each Array Element has it's own relation defined)

Displayed fields

How does Axapta determine which fields to use?

Axapta uses a simple system to determine which fields to display in an automatically created lookup.
If no special changes are made, then the fields shown on the lookup are determined by the following information from the base table:
  1. The field(s) responsible for the relation (in the order of the content of the relation-treenode of the table or the extended datatype)
  2. TitleField1
  3. TitleField2
  4. The first field of every index of the table (in the order of the index-id)
A maximum of six fields will be shown, and duplicates will be removed.

The standard lookup for inventory items
To see this logic, look at the standard ItemId lookup (for example, from a newly-created sales line) in the standard application.

Properties and indexes for the InventTable
The fields shown are as follows (with field names in brackets)
  1. Item number (ItemId)
  2. Item name (ItemName)
  3. Item group (ItemGroupId)
  4. Search name (NameAlias)
  5. Item type (ItemType)
  6. Dimension group (DimGroupId)
See the image to the right for the relevant properties of the InventTable table.
The first two fields are taken from the TitleField1 and TitleField2 properties of the table. The rest come from the indexed fields in the order shown. The first index contains ItemId, which is a duplicate of the field specified in TitleField1 and is therefore skipped. The second index contains ItemGroupId, the third column in our lookup, and ItemId which is again skipped. The third index contains only NameAlias, which is the fourth column on our lookup, and so on, until the maximum of six fields is reached or no more indexes are found.

How can we change which fields are displayed?

In general, it wouldn't be advisable to change either the TitleField properties, or the indexes, purely to change what is displayed on a lookup form. Luckily, Axapta gives us as easier way to achieve the same goal.
If the AutoLookup field group on the base data table has been filled, then those fields will be used irrespective of the usual logic. Modifying this field group is the easiest way to change which fields appear in lookups against that table.
Bear in mind that while you can add display and edit methods to your AutoLookup field group, the values will not display correctly unless all required fields for calculations are also included in the field group. For example, if you want to show the name of a vendor, based on the VendAccount stored on a record, then the VendAccount itself must also be included in the group. This is because the lookup query only fetches the fields from the database which are actually to be displayed, rather than the entire record.

Manual lookups

Calling the standard lookup behaviour from code

It is simple to call the standard Axapta lookup functionality from code. This allows the programmer to specify that a lookup will be based on a non-standard field or data type.
To hook into the lookup system, you can override the lookup method at the form control. It is useful to first understand what happens "under the hood" before any changes are made.
If the control is a "bound field", that is, the control has DataSource and DataField property values, then the kernel will perform a call to performDBLookup() during the super() call. It passes the tableId and fieldId from the property values to the kernel code which creates the lookup. Relations which are set directly on the specified table will be used to create the lookup if available, or the standard EDT relations otherwise.
If the control is unbound, but has a related Extended Data Type (either set directly on the control or from the signature of an associated edit method), then a performTypeLookup() call is made in super(). This has no associated table, and can therefore not use any table level relations. Therefore the lookup is based purely on the relations specified on the EDT.
With this knowledge in mind, we can modify the standard lookup functionality by passing through different parameters to the performDBLookup and performTypeLookup methods.

Changing the lookup form used

There are two possibilities when specifying a custom lookup form.

Construct a standard lookup form, based on your own query

Axapta provides a mechanism whereby we can create a standard lookup form programmatically, to easily allow us to perform a custom lookup using a query which is too complicated for the relations system to express, or where the requirement is unique and we do not wish to set up relations, which will have a global effect.
See the article on the sysTableLookup class for more information about using this method.

Use an entirely new lookup form

It is possible to create an entirely new form, following certain guidelines, and use it as a lookup. See the Lookup Form article for more information.

SysTableLookup class - Axaptapedia

Get it from SysTableLookup class - Axaptapedia:

The SysTableLookup class is provided by the standard application to allow programmers to easily create their own lookup forms, in code.
The basic steps to using this class are as follows:
  1. Create the sysTableLookup object
  2. Create the query which will be used to select the lookup data
  3. Specify the fields which will be shown on the lookup
  4. Perform the lookup
In this example, we will perform a complex lookup on the customer table. We only want to include customers which are not blocked, and where one or more open transactions exists.
public void lookup()
Query query = new Query();
QueryBuildDataSource dsCustTable;
QueryBuildDataSource dsCustTrans;

// Instantiate sysTableLookup object using table which will provide the visible fields
SysTableLookup sysTableLookup = sysTableLookup::newParameters(tableNum(CustTable), this);

// Create the query. Only select customers where blocked != All and one more more transactions
// exist with no closed date
dsCustTable = query.addDataSource(tableNum(CustTable));
dsCustTable.addRange(fieldNum(CustTable, Blocked)).value(queryNotValue(CustVendorBlocked::All));

dsCustTrans = dsCustTable.addDataSource(tableNum(CustTrans));
dsCustTrans.addRange(fieldNum(CustTrans, Closed)).value(queryValue(dateNull()));

// Set the query to be used by the lookup form

// Specify the fields to show in the form. In this case we have chosen
// Account number, name, and dimension one.
sysTableLookup.addLookupfield(fieldNum(CustTable, AccountNum));
sysTableLookup.addLookupfield(fieldId2Ext(fieldNum(CustTable, Dimension), 1));

// Perform the lookup
While the above example will work perfectly, you should consider moving this code out of the lookup method on the form control itself. For ease of re-use and to maximise ease of upgrading of the forms, it is better to construct the lookup as a static method on the CustTable which can then be called from the form. Don't forget to remove the super() call from the method. Otherwise your Lookup won't work.
For example:
public static void lookupCustOpenTrans(FormControl _callingControl)
Query query = new Query();
QueryBuildDataSource dsCustTable;
QueryBuildDataSource dsCustTrans;

// Instantiate sysTableLookup object using table which will provide the visible fields
SysTableLookup sysTableLookup = sysTableLookup::newParameters(tableNum(CustTable), _callingControl);

... remainder of code from above ...
In the form control lookup() method:
public void lookup()

Get day, month and year from date in axapta x++

In Dynamics AX, sometimes we need to get the day, month or year from a date and we don't know how to do this... but we can do this easily...

//Get day from date

//Get month from date

//Get year from date

Passing Parameters to a Report in Dynamics AX « Rehan Aqeel's Blog

Passing Parameters to a Report in Dynamics AX « Rehan Aqeel's Blog:

Creating reports in AX is generally ‘a walk in the park’ even for the new developers not fully acquaint with the syntax of X++. However, it sometimes becomes challenging to understand how the parameters could be passed to a report when you want to initiate that report from a form.

Let’s look at an example where you may want to create a ‘Purchase Requisition Report’ that the users could generate to see the status of each purchase requisition and the associated workflow entries for that Purchase Requisition.
I will not go into the details of how to develop this report, but you should know that such a report do not exist in the out-of-the-box functionality within AX 2009.
So let’s say that you have developed this report and now when you generate this report you can pass on the required ‘Purchase Requisition ID’ in the ‘Parameter Prompt’ of the report to view the particular PR details accordingly.
However, now in the next step you want to call this report from the ‘Purchase Requisition Form’ (i.e PurchReqTable). To do this, you should first create a ‘Button’ within the ButtonGroup on the form.
Now right-click on the ‘Methods’ node within the newly created button and choose ‘Override Method –> clicked’
Within the clicked function, you should write the following code;
void clicked()
Args args = new args();
ReportRun reportRun;
reportRun = classFactory.reportRunClass(args);
The above code calls the args() system class. This class is used to pass arguments to a class-constructor. You can pass information such as name, caller, and parameters to a new class. This code passes the relevant Purchase Requisition ID (which is currently selected by the user on the form) to the report ‘PurchRequisitionDetails’ in the above code.
Now, you need to go to the report (which in this case is PurchRequisitionDetails). Right-Click on the methods node of the Report and click on ‘Override Method –> init’
In this init method, you need to enter the following code to allow the report to read the parameters from the form.
public void init()
.addRange(fieldnum(PurchReqTable, PurchReqId)).value(element.args().parm());
info(“Error in init method”);
Once you have got the above code correctly entered, you should now be able to generate your report directly from the form.