Monday, 1 July 2013

Get Current Company in AX 2009

static void curExtExample(Args _arg)
{
    str curCompany;
    ;
 
    // Sets curCompany to the extension of the current company.
    curCompany= curExt();
    print "Current extension is " + curCompany;
    pause;
}

Todays date in ax 2009 report

To Get the todays date in the Ax 2009 report write the following code in display method of the report

display public str ABC_TodaysDate()
{
    return date2Str(today(), 123, DateDay::Digits2, DateSeparator::Slash, DateMonth::Digits2, DateSeparator::Slash, DateYear::Digits4);
}

Wednesday, 20 March 2013

Passing Args from Form to Class in Dynamics Ax 2012

In this post, i will demonstrate on how to pass Args from Form to Class in Dynamics Ax.


This post will helpful for those who are keen to learn about Args which is very much fruitful concept in Dynamics Ax.

The Scenario is when I select multiple grids in Form , those records will be passed to Class and once you received those records in Class and you can use it as per your Requirement.

Firstly, make one form from which you will pass the arguments and drag your table to the datasource, then drag the fields to the grid of design node, also drag one button adn override the clicked method.

write the following code in clicked method.
void clicked()
{
int recordsCount;
SampleTbl _SampleTbl;
container con;
Args args;
str multiSelectString;
;

args = new Args();
recordsCount = SampleTbl_ds.recordsMarked().lastIndex(); // gets the total records selected
_SampleTbl = SampleTbl_ds.getFirst(1);

while (_SampleTbl)
{
// storing recid of selected field in container
con = conIns(con,1,_SampleTbl.RecId);

// converting container to string with comma separated
multiSelectString = con2Str(con,',');

_SampleTbl = SampleTbl_ds.getNext(); // moves to next record
}
// passing string
args.parm(multiSelectString);
// calling menu item
new MenuFunction(identifierstr(SampleTest), MenuItemType::Action).run(args);


}

first
make one class and write the following code in main method of it.
public static void main(Args args)
{
SampleTbl _SampleTbl;
container con;
int i;
str multipleRecords;
;
multipleRecords = args.parm();
info(strFmt('%1',multipleRecords));
// i am just here an infolog of recids but you can do as per requirement once you got multiple records
}


thanks and your feedback will be appreciated

Passing Multiple Records from one form to another through Args in Dynamics Ax 2012


In my last post, i posted on how to pass Record from one Form to another Form. Now i will pass multiple Record from one Form to another through Args.


The Scenario is when I select multiple grids in Form A, those records will be passed to FormB and there FormB will received the all those records and filter it and will show.

Step 1: Make one SampleTable which has three fields named (SIno, name, AddressCity).
Step 2: Make FormA with datasource as SampleTable and drag the datasource fields into the design Grid.
Step 3: Drag one button and override the click method and write the following code.
step 4: Make one Display menuitem of FormB.


void clicked()
{

int recordsCount;
SampleTable _sampleTable;
container con;
Args args;
str multiSelectString;
;


args = new Args();
recordsCount = SampleTable_ds.recordsMarked().lastIndex(); // gets the total records selected
_sampleTable = SampleTable_ds.getFirst(1);

while (_sampleTable)
{
// storing recid of selected field in container
con = conIns(con,1,_sampleTable.RecId);

// converting container to string with comma separated
multiSelectString = con2Str(con,',');

_sampleTable = SampleTable_ds.getNext(); // moves to next record
}
// passing string
args.parm(multiSelectString);
// calling menu item
new MenuFunction(menuitemDisplayStr(FormBMenuItem), MenuItemType::Display).run(args);
}


first

step 5: Make FormB with datasource as same table for which you take for Form A i.e., SampleTable and drag the fields in to the
Grid of design part.
step 7: write the following code in to the init method of FormB.


public void init()
{
container con;
int i;
str multipleRecords;
super();
// getting string value from caller
multipleRecords = element.args().parm();

// string to container
con = str2con(multipleRecords,",");

// for sorting
for(i = 1;i<= conLen(con) ;i++)
{
SampleTbl_ds.query().dataSourceTable(Tablenum(SampleTbl)).addRange(fieldNum(SampleTbl,RecId)).value(SysQuery::value(conPeek(con,i)));
}

}


thanks and your feedback will be appreciated.

Tuesday, 19 March 2013

Passing Args from one Form to another Form in dynamics Ax 2012

Args concept in dynamics ax is awesome. one can easily pass arguments from one Form to another Form with very less effort. Here, i am going to demonstrate how to pass Arguments from Form to Form. The Scenario is when I select one grid in Form A, that record will be passed to Form B and there Form B will received the whole record and filter it and will show.

Step 1: Make one SampleTable which has three fields named (SIno, name, AddressCity).
Step 2: Make FormA with datasource as SampleTable and drag the datasource fields into the design Grid.
Step 3: Drag one button and override the click method and write the following code.

void clicked()
{
Args args;
FormRun formRun;
;
super();
args = new args(formstr(FormB)); // sending Args(record) to FormB
args.record(SampleTable);
formrun = classfactory.formrunclass(args);
formrun.init();
formrun.run();
formrun.wait();
formrun.detach();

}



first

step 4: Make FormB with datasource as same table for which you take for Form A i.e., SampleTable and drag the fields in to the
Grid of design part.

step 5: write the following code in to the init method of FormB.

public void init()
{
SampleTable _sampleTable;
super();
_sampleTable = element.args().record();
SampleTable_ds.query().dataSourceTable(Tablenum(SampleTable)).addRange(fieldNum(SampleTbl,RecId)).
value(SysQuery::value(_sampleTable.Recid));
}

Note: You can pass only one Record with this Code, if you want to pass multiple grids,i will cover in next post.


thanks and your feedback will be appreciated.

Monday, 25 February 2013

Using Tree in Form

1. Firstly, create three tables with the following requirements.

1.1 Create a table (parent table) name: Medicine

Fields type Edt
MedName str
MedDesc str

1.2. Create a table (reference table) name: MedReferencehrr

Fields type Edt
MedRef int64 Medref = reference table: Medicines
DtOwn int64

Relation:
1. ownrelation : MedReferencehrr i.e, DtOwn == recid
2. Foreign key rel : Medicines MedRef = MedReferencehrr .recid



1.3 Create a table( child table ) name : MedDetails

Fields type Edt

MedRef int64 Medref = reference table: Medicines
Name1 str
Desc1 str

Relation: Normal: MedDetails .MedRef = Medicines .recid

1.4 Create a new Form named SampleTree2 and drag 3 tables in the form DS. The following code
must written as it is.


Medicines no relation
MedDetails join source: Medicines type: active
MedReferencehrr
In design: add group in group add a Tree name it as: SampleTree2

Public class FormRun extends ObjectRun
{

boolean isCreatedNew;
boolean isModified;
TreeItemIdx newItemIdx;
TreeItemIdx lastRecordIdx;
int64 lastRecordRecId;
String10 billingGroupRecid;


//
String10 billingeGroupHierarchyRecid;
int64 billingGroupHierarchyParentRecid;


//
QueryBuildRange qbrMedecines;

QueryBuildRange qbrMedReferencehrr;

//
List delRecList;
//

ImageListAppl_HISServices imageAppl;
#define.Root(3)
}
1. Init method :

public void init()
{
super();
imageAppl = new ImageListAppl_HISServices();
imageAppl.addImage(resourceStr(SampleTree),#Root);
SampleTree.setImagelist(imageAppl.imageList());
}

2. Run method :
public void run()
{
super();
if( Medecines.RecId == 0)
{
AddNewService.enabled(true);
}
element.loadTree();

}
3. Loadtree method:

public void loadTree()
{
TreeItemIdx parentItemIdx;

SampleTree2.deleteAll();

parentItemIdx = this.createRootNode();

this.createChildNodes(parentItemIdx,0);

SampleTree2.select(SampleTree2.getRoot());
SampleTree2.expand(SampleTree2.getRoot());
}

4. createRootNode method :

public TreeItemIdx createRootNode()
{
FormTreeItem parentItem;

parentItem = new FormTreeItem("Medicines");
parentItem.data(0);

//parentitem.image(imageAppl.image(#Root));
// parentitem.selectedImage(imageAppl.image(#Root));

returnSampleTree2.addItem(FormTreeAdd::Root,FormTreeAdd::First,parentItem);
}

5. createChildNodes method :

public void createChildNodes(TreeItemIdx _parentIdx, int64 _serviceGroupHierarchyParentRecid)
{
MedReferencehrr MedReferencehrrLocal;
MedReferencehrr MedReferencehrrChild;
Medecines medecines1;
FormTreeItem parentItem;
TreeItemIdx newParentIdx;

while select * from MedReferencehrrLocal
join * from medecines1
where MedReferencehrrLocal.DtOwn == _serviceGroupHierarchyParentRecid
&& MedReferencehrrLocal.MedRef == medecines1.RecId
{

select count(recId) from MedReferencehrrChild
where MedReferencehrrChild.DtOwn == MedReferencehrrLocal.RecId;

if(MedReferencehrrChild.RecId > 0)
{
parentItem = new FormTreeItem();
parentItem.data(MedReferencehrrLocal.RecId);
parentItem.text(medecines1.MedDesc);


newParentIdx = SampleTree2.addItem(_parentIdx,FormTreeAdd::Sort,parentItem);
if(MedReferencehrrLocal.RecId == lastRecordRecId)
{
lastRecordIdx = newParentIdx;
}
element.createChildNodes(newParentIdx,MedReferencehrrLocal.RecId);
}
else
{
parentItem = new FormTreeItem();
parentItem.data(MedReferencehrrLocal.RecId);
parentItem.text(medecines1.MedDesc);


newParentIdx = SampleTree2.addItem(_parentIdx,FormTreeAdd::Sort,parentItem);
if(MedReferencehrrLocal.RecId == lastRecordRecId)
{
lastRecordIdx = newParentIdx;
}
}

}

}



Now add action panel to this tree group . in button group add two buttons type : button name :AddBelow and delete .
In AddBelow button : clicked method :
void clicked()
{
super();
element.addNode(SampleTree2.getSelection());
}
In form Methods : add the method:
addNode method :

public void addNode(TreeItemIdx _parentIdx)
{
FormTreeItem newItem;
FormTreeItem parentItem;

newItem = new FormTreeItem("");
newItem.data(0);
//newItem.image(imageAppl.image(#NormalGroup));
//newItem.selectedImage(imageAppl.image(#NormalGroup));

newItemIdx = SampleTree2.addItem(_parentIdx, FormTreeAdd::Sort,newItem);

SampleTree2.select(newItemIdx);

Medecines_ds.create();

parentItem = SampleTree2.getItem(_parentIdx);
billingGroupHierarchyParentRecid = parentItem.data();
isCreatedNew = true;

AddBelow.enabled(false);
}

In Delete button : clicked method :
void clicked()
{
//super();
FormTreeItem treeItem;

treeItem = BillingTree.getItem(BillingTree.getSelection());

if(element.deleteBillingGroup(treeItem.data()))
{
element.loadTree();
}

}


In form Methods : add the method:
deleteBillingGroup method :
ignore error and cont
public boolean deleteBillingGroup(recId _recId)
{
Medecines medecines2;
MedReferencehrr medReferencehrrlocal;

DialogButton dialogButton;
ListEnumerator enumer;
boolean allDeleted = true;

if(_recId)
{
medReferencehrrlocal = MedReferencehrr::find(_recId);


dialogButton = Box::yesNo('Selected billing group and its subsidary group will be deleted', DialogButton::No);
if( dialogButton == DialogButton::Yes )
{
try
{
delRecList = new List(Types::Int64);

delRecList.addStart(medReferencehrrlocal.MedRef);

element.deleteGroupCode(_recId);

enumer = delRecList.getEnumerator();

ttsBegin;

while(enumer.moveNext())
{
select forupdate medecines2
where medecines2.RecId == enumer.current();

if(medecines2.validateDelete())
{
medecines2.delete();
}
else
{
allDeleted = false;
break;
}
}

if(allDeleted)
{
ttsCommit;
return true;
}
else
{
ttsAbort;
return false;
}

}
catch
{
return false;
}
}
else
{
return false;
}
}


else
{
return false;
}
}
--
In Table MedReferencehrr(In Table not in Form) Create a new method ,write the following code :

public static MedReferencehrr find(
RecId _recid,
boolean _forUpdate = false,
ConcurrencyModel _concurrencyModel = ConcurrencyModel::Auto)
{
MedReferencehrr medReferencehrr ;
medReferencehrr.selectForUpdate(_forUpdate);

if(_forUpdate && _concurrencyModel != ConcurrencyModel::Auto)
{
medReferencehrr.concurrencyModel(_concurrencyModel);
}

select firstonly * from medReferencehrr where medReferencehrr.RecId == _recid;

return medReferencehrr;
}


------
Come Back to Form and Create a New Method In form name : deleteGroupCode


public void deleteGroupCode(recId _parentrecId)
{
MedReferencehrr medReferencehrrChild;
MedReferencehrr medReferencehrrTraverse;

while select * from medReferencehrrTraverse
where medReferencehrrTraverse.DtOwn == _parentrecId

{

select count(recId) from medReferencehrrChild
where medReferencehrrChild.DtOwn == medReferencehrrTraverse.RecId;

if(medReferencehrrChild.RecId > 0)
{
delRecList.addEnd(medReferencehrrTraverse.MedRef);
element.deleteGroupCode(medReferencehrrTraverse.RecId);

}
else
{
delRecList.addEnd(medReferencehrrTraverse.MedRef);
}

}
}


In Form DesignDesigngroupTree SampleTree2 --right click – override method – SelectionChanged :

public void selectionChanged(FormTreeItem _OldItem, FormTreeItem _NewItem, FormTreeSelect _how)
{
super(_OldItem, _NewItem, _how);

if(SampleTree2.getRoot() == SampleTree2.getSelection())
{
AddNewService.enabled(false);
}
else
{
AddNewService.enabled(true);
}

if(isCreatedNew)
{
if(isModified)
{
if(SampleTree2.getSelection() != newItemIdx)
{
//if(HMServiceCatalog_ds.validateWrite())
//{
//HMServiceCatalog_ds.write();
//}
//else
//{
SampleTree2.select(newItemIdx);
//}
}

}
else
{
SampleTree2.delete(newItemIdx);
newItemIdx = 0;
if(Medecines_ds.validateWrite())
{
Medecines_ds.write();
}
isCreatedNew = false;
isModified = false;
AddBelow.enabled(true);
billingeGroupHierarchyRecid = element.getCurrentSelectedItemRecid();
MedReferencehrr_ds.executeQuery();
billingGroupRecid = int642str(MedReferencehrr.MedRef);
Medecines_ds.executeQuery();

}
}
else
{
billingeGroupHierarchyRecid = element.getCurrentSelectedItemRecid();
MedReferencehrr_ds.executeQuery();
billingGroupRecid = int642str(MedReferencehrr.MedRef);
Medecines_ds.executeQuery();

}
}



Now design the form. Take another Group , take action panel with two method,
Name Prop
AddNewService command : New
DeleteNewService command : DeleteRecord

Select a new grid and drag some fields from the Table : MedDetails

In Form DataSource :
1. Medecines

public void init()
{
super();

qbrMedecines = this.query().dataSourceTable(tableNum(Medecines)).addRange(fieldNum(Medecines,recId));
}
public void write()
{
MedReferencehrr MedReferencehrrLocal;

super();

if(isCreatedNew == true)
{
MedReferencehrrLocal.MedRef = Medecines.RecId;
MedReferencehrrLocal.DtOwn = billingGroupHierarchyParentRecid;
MedReferencehrrLocal.insert();

newItemIdx = 0;
billingGroupHierarchyParentRecid = 0;
isCreatedNew = false;
isModified = false;
AddBelow.enabled(true);

element.refresh(MedReferencehrrLocal.RecId);
}
else
{
element.refresh(MedReferencehrr.RecId);
}
}
public void executeQuery()
{
qbrMedecines.value(billingGroupRecid);

super();
}

2. MedReferencehrr

public void init()
{
super();

qbrMedReferencehrr = this.query().dataSourceTable(tableNum(MedReferencehrr)).addRange(fieldNum(MedReferencehrr,recId));
}

public void executeQuery()
{
qbrMedReferencehrr.value(billingeGroupHierarchyRecid);

super();
}






Lastly Create a new method in Form Method :

public void refresh(recId _lastRecid)
{
lastRecordRecId = _lastRecid;

element.loadTree();

SampleTree2.select(lastRecordIdx);
}






Now : In order to Sort the Tree Based on the following upper grid then :

1. Create a new Table MainTableMed
Add few fields
In Table Medecines :
Add relation  new relation give table : MainTableMed;
Right click foreign key PrimaryKey
A field will be generated .

2. In the Form Drag Table : MainTableMed into Datasource ..
InDatasourceTable: Medecines Properities
Join Source = MainTableMed
Link Type = active

In Form DataSource Table MainTableMed  override methods :

public void create(boolean _append = false)
{
super(_append);

SampleTree2.deleteAll();
AddBelow.enabled(false);
}

public void delete()
{
super();

if(MainTableMed.RecId == 0)
{
SampleTree2.deleteAll();
AddBelow.enabled(false);
}

}
public int active()
{
int ret;

ret = super();

if(ret)
{
if(MainTableMed.RecId)
{
element.loadTree();
AddBelow.enabled(true);
}
else
{
SampleTree2.deleteAll();
AddBelow.enabled(false);
}
}

return ret;
}
2

To work this Moddify the form method : CreateChildNodes


Now design the Form  take Group , add action panel contains New and Delete record Methods and a Grid : pro -datasource : MainTableMed , add few fields
1

Sunday, 24 February 2013

Microsoft Dynamics Ax Macros

In MorphX macros are not commonly used. A few places make use of macros such as keeping track of the list of fields stored when using dialogs. It is recommended only to use macros to define constants. Also supports code, but is not recommended as reusing code from macros is not flexible.




The main difference between a macro and a method is that a macro has no variable declaration part, and the code in a macro is not validated for errors before executed from a method. This is another reasons for not putting code in macros.

When using macros in your code, the macros must be declared after the variable declaration. And the common place to put the definition is in the ClassDeclaration of a class, form or a report. This will make the macro definition available for all parts of the object.


Macro commands:

For writing macros a set of simple macro commands are used. Below are few examples.


















































































Command

Description

#define

Used to define a constant.

AxExample: See macro HRMConstants.

Syntax: #define.myConstant100(’100′)

#if.empty

Will return true if the macro has not been called with the parameter validated in the statement.

#if.notempty

Will return true if the macro has been called with the parameter validated in the statement.

AxExample: See macro InventDimJoin

Syntax: #if.notempty(%3)
print %3;
#endif

#endif

Ends a #if.empty or a #if.notempty statement.

AxExample: See macro InventDimJoin

Syntax: #endif (following any if statement)

#globalmacro

No difference whether declaring the start of a macro with #localmacro or #globalmacro. #globalmacro is not used in the standard package, consider using #localmacro instead.

#localmacro

Specify the start of a local macro.

AxExample: See macro BOM

Syntax: #localmacro.BOMDateSelect
(((BOM.fromDate <= %1 || ! BOM.fromDate) && (BOM.toDate >= %1  || ! BOM.toDate))  || ! %1 )
#endmacro

#endmacro

Ends a #LOCALMACRO or a #GLOBALMACRO.

#linenumber

Returns the current line number of the macro. Can be used while debugging, but not of must use.

#macrolib

Used to load an AOT macro from code.

AxExample: See class method BOMHierarchy.searchDownBOM()

Syntax: #macrolib.MyMacro

#undef

Undefine a constant declared with #DEFINE. A defined constant cannot be used if #undef is called with the define name.

Syntax: #define.MyConstant(100)
print #MyConstant;
#undef.MyConstant
print #MyConstant; // will fail, as #MyConstant is not defined.


Defining Constants:
Instead of using text in your code it is strongly recommend defining your text as constants. Often you will need an integer or a text for setting a value. If you are going to set RGB color it is not easy to read the following:

myStringColor(255, 255, 255)
Instead you should consider defining a constant with a descriptive name:

myStringColor(#RBGColorWhite)

Using a macro as a constant rather than entering the value in code makes it easier tomaintain. A good way to organize the constants used in your modifications is by creating a macro in the AOT for keeping all your constants in one place, one good example is HRMConstants.

Creating Macros:

Macros are either created directly in the code, or put in an AOT macro and then the AOT macro is declared in the code.

Example(1): #localmacro created in the code

static void Macros_LocalMacro(Args _args)

{

CustTable custTable;

;

#localmacro.selectCustTable  //Macro definition starts here

#ifnot.empty(%1)

while select %1

#ifnot.empty(%3)

order by %3

#endif

{

info(queryValue(%1.%2));

}

#endif

#if.empty(%1)

info(“No table specified.”);

#endif

#endmacro  //Macro definition ends here

#selectCustTable(CustTable, accountNum)  //Calling Macro with valid parameters

#selectCustTable  //Calling Macro with no parameters – output will be text “No table specified” as per the validation.

}

The macro will select records from a table ‘CustTable’ and print a field from the same as the table to be fetched, and the fields (%1, %2, %3) to be printed are specified in the parameters for the first Macro call.
In the second Macro call, the table has not been specified so text will be printed to the Infolog.
As you cannot declare variables in a macro, integer values prefixed with a percentage sign such as %1 are used instead. This is the common way of using the macros. The validations must be before calling the macro. Notice that you can call a macro without entering the parentheses after the macro name.

Example(2): Create and use an AOT Macro
If your macro is going to be used in several places it would make sense creating the macro in the AOT as you will then be able to reuse the macro.
To create a new macro in the AOT:

1.       Unfold the Macro node, right-click and choose New Macro.

2.      A new empty macro node will be created. You can rename the new macro by opening the property sheet to “MyFirstMacro”

3.      Now paste the code of the #localmacro (from above) to your new macro.

4.      Save the Macro, and it is ready to use.

To use the macro created in the AOT the macro command #macrolib is used. Here the AOT macro is name MyFirstMacro, and it can be used in the code as shown below.

static void Macros_MacroLib(Args _args)

{

CustTable custTable;

;

#macrolib.MyFirstMacro

#selectCustTable(CustTable, accountNum)

#selectCustTable

}

Even this will result in the same output as explained above, the only difference is that we are calling a Macro created in AOT using #macrolib command.




Using tree controls

X++ Implementation of few SQL Keywords

As we already saw in the Previous post, In X++, we can directly use database related statements similar to any other code. Here, we will see and understand how to implement few well-known SQL keywords in X++.




Example(1): To print records in custTable in descending order.
while select custTable order by custTable.AccountNum desc
{
print(strfmt(“%1, %2″, custTable.accountNum, custTable.Address));
}
pause;

Output:



By using order by clause similar to the SQL queries with the keyword ‘desc’, we are able to achieve the expected output.


Example(2): To print Average of Amount from custTrans table.
while select avg(AmountMST) from custTrans
{
print(custTrans.AmountMST);
}
pause;

Output:

Here, we are using while select statement with the Aggregate keyword ‘avg’ on the required field to get the Average of all the values of AmountMST in the table.
Also note that to print the output, You can get the result from the same field, i.e, custTrans.AmountMST.

The below are Details, Syntax and an AX Example respectively for few well-known SQL keywords:












































































































































































































































































KeywordExample
ascSet the sorting order to ascending. All selects are default fetching data ascending.
Syntax: select custTable order by accountNum asc;
descSet the sorting order to descending. Used in combination with order by or group by.
Syntax: select custTable order by name desc;
AX Example: See table method CustTable.lastPayment().
avgSelect uses aggregate keyword (avg) using only one call to the database calculating a result based on multiple records
Syntax: select avg(amountMST) from custTrans;
AX Example: See class method KMKnowledgeCollectorStatisticsExecute.runQuery().
countAggregate keyword used to count the number of records fetched.
Syntax: select count(recId) from custTrans;
AX Example: See class method KMKnowledgeCollectorStatisticsExecute.runQuery().
sumAggregate keyword used to sum values of a field fetched.
Syntax: select sum(amountMST) from custTrans;
AX Example: See class method KMKnowledgeCollectorStatisticsExecute.runQuery().
maxofAggregate keyword used to return the highest field value fetched
Syntax: select maxOf(amountMST) from custTrans;
AX Example: See class method KMKnowledgeCollectorStatisticsExecute.runQuery().
minofAggregate keyword used to return the lowest field value fetched.
Syntax: select minOf(amountMST) from custTrans;
AX Example: See class method KMKnowledgeCollectorStatisticsExecute.runQuery().
delete_fromWill delete multiple records in one call to the database.
Syntax: delete_from myTable where myTable.amountMST <=’1000′;
AX Example: See class method InventCostCleanUp.updateDelSettlement().
exists joinExists join is used to fetch records where at least one record in the secondary table matches the join expression.
No records will be fetched from the secondary table using exists join.
Syntax: while select custTable exists join custTrans
where custTable.accountNum == custTrans.accountNum
AX Example: See class method InventAdj_Cancel.cancelInventSettlements().
notexists joinOpposite of exists join. Will fetch records from the primary table, where no records in the secondary table match the join expression.
Syntax: while select custTable notexists join custTrans
where custTable.accountNum == custTrans.accountNum
AX Example: See class method InventConsistencyCheck_Trans.run().
outer joinOuter join will select records from both tables regardless if there are any records in the secondary table matching the join expression.
Syntax: while select custTable outer join custTrans
AX Example: See class method SysHelpStatistics.doTeams().
joinJoin will fetch Records matching the join expressionfrom both tables. (innerjoin)
Syntax: while select custTable join custTrans
where custTable.accountNum == custTrans.accountNum
AX Example: See table method SalesTable.LastConfirm().
firstfastInstruct to select the first record faster. used in situations where only one record is shown, like in a dialog.
Syntax: select firstfast custTable order by accountNum;
AX Example: See class method ProjPeriodCreatePeriod.dialog().
firstonlyFirst record will be selected. Firstonly should always be used when not using while in selects.
Syntax: select firstonly custTable where custTable.AccountNum == _custAccount (variable)
AX Example: See Table method CustTable.find().
forupdateUsed If records in a select are to be updated
Syntax: while select forupdate reqTransBOM where reqTransBOM.ReqPlanId     == this.ReqPlanId
AX Example: See Table method ReqTrans.deleteExplosionCoverage().
fromDefault all fields of a table is selected. From is used to select only the fields specified.
Use it for optimization only, as it makes the code more complex.
Syntax: select accountNum, name from custTable;
group bySort the fetched data group by the fields specified. Only the fields specified in the group by will be fetched.
Syntax: while select custTable group by custGroup;
AX Example: See class method InventStatisticsUS.calcTotals().
indexUsed to set the sorting order of the fetched data. The kernel will convert the keyword index to an order by using the fields from the index.
Index should only be used if the fetched data must be sorted in a specific way, as the database will choose a proper index.
Syntax: while select custTable index accountIdx.
index hintIndex hint will force the database to use the specified index.
Syntax: while select custTable index hint accountIdx.
AX Example: See Table method ReqTrans.deleteExplosionCoverage().
insert_recordsetUsed to insert multiple records in a table. Insert_recordset is useful when copying data from one table to another as it only requires one call to the database
Syntax: insert_recordset myTable (myNum,mySum)
select myNum, sum(myValue) from anotherTable group by myNum where myNum <= 100;
AX Example: See class method SysLicenseCodeReadFile.handleDomainLicenseChanges().
update_recordsetUsed  to update multiple records in one database call. Useful to initialize fields in a fast way.
The fields updated are specified after thekeyword setting.
Syntax: update_recordset myTable setting field1 = myTable.field1 * 1.10;
AX Example: See class method ProdUpdHistoricalCost.postScrap().

Parent Link: Using Select statement in X++ to retrieve data




passing parameters between forms in AX

In dynamics AX, working with forms, there are times when you need to pass some information from current form to the opened form, so the question arrived is that what’s the best way to open the new form and pass information.




Answer: It depends upon the information that is needed in the new form; there is Args class that plays an important role to pass the information. Let’s take a look on some of the important methods of that class

Args class (Argument)
“The Args class is used to pass arguments such as a name, a caller, and parameters between application objects”

Some important methods are
































Caller


Gets or sets the instance of the object that created this instance of the Args class.

name


Gets and sets the name of the application object to call.

parm


Gets or sets a string that specifies miscellaneous information for the called object.

parmEnum

Gets or sets the enumeration value of the enumeration type that is specified in the parmEnumType method.

parmEnmType


Gets or sets the ID value of any enumeration type.

ParmObject


Gets or sets an instance of any object to pass to the called object.


record


Gets and sets the record from the table on which the caller object is working.

There are four methods that can be used to pass extra information to the new class:



  1. The parm method – to pass strings


  2. The parmEnum and parmEnumType method – to pass enumeration values


  3. The parmObject method – to pass an object of any type.


Examples:
1.      If you need a data from the parent form main data source for the current record, so you don’t need to do anything in parent, just create a display menu item and give the form name that needs to be opened, create a menuItem button and assign the newly created menu item.

Override the Init method on opened form

And you get the parent dataset records as

element.args().record()

2.      Need to pass any object/string/Enum

Use the same approach for creating the button
Parent form

void clicked()
{
Args args;
FormRun formRun;super(); 

args = new Args(formstr(FormName));


 // To pass any string value
args.parm(<string value>);

 // To pass any object
args.parmObject(<object>);

 // To pass any Enum

       args.parmEnum( EnumValue);
args.parmEnumType( EnumNum( <EnumName>) );

 formRun = classFactory.FormRunClass(args);
formRun.init();
formRun.run();
formRun.wait();
formRun.detach();
parenttable_ds.refresh(); // Refreshing parent table DataSourceTable
parenttable_ds.executeQuery(); // Refreshing Parent DataSourceTable
}

Child Form

void init()
{
args = element.args();

    // get string parameter
<string> = args.parm();

    // get object parameter

    <object> = args.parmObject();

    // get enum parameter
if( element.args().parmEnumType() == EnumNum( <EnumName>) )
{
<enum contol/variable>  =( element.args().parmEnum() );
}

}3.      There are many parameters that you need to pass to the child form. 


               In that scenario, you need to create an extra class (parameter/contract class), you can first set the parameters in the init method for that class, use the parmObject for setting and gets the object on the child form

=======================================================================================


Argument Passing between Forms in Dynamics Ax 2009



Here a sample code to pass argument to one form to another form and using of Args() class.
Steps:
1) Create two Forms named FormA and FormB
2)Use the EmplTable as the Datasource of both forms
3)Design FormA with one Grid and add 4 data fields to the Grid(EmplId,DEL_Name,Grade,EmplStatus…..)
4)Assign the datasource for the grid and the data fields
5)Add a Button in FormA
6)Override the Clicked() method and write the below code:
void Clicked()
{
Args    _args;
FormRun _formRun;
EmplId   _empId;
;
_empId = EmplTable.EmplId;  // Selected employee id in the Grid is assigned to the variable which is pass to the next form
_args = new Args(); // creating a object for args class
_args.name(formstr(VA_FormB));  // Form Menuitem
_args.caller(this);  // Form Caller(Current Form is mentioned as this)
_args.parm(_empId); // Employee Number is passed to next form[but parm() is not a best practise]
_args.record(EmplTable); // Table name is passed
_formRun = ClassFactory.formRunClass(_args); //new FormRun(_args);   // Creating object for FormRun
_formRun.init();   // Form Initialization for Load
_formRun.run();  // Form Run for process
_formRun.wait(); // Form Wait for Display
}
7) Open the Second Form – FormB
8) Add one Grid Control and set the Data Source is EmplTable
9) Add 4 data fields as same in the Form A
10)Now Override the Init() of Form
public void init()
{
parmid      _parmId;
EmplTable   _EmplTable;
//     DictTable   _dictTable;    FormBuildDataSource   _ds;    FormBuildGridControl frmGrid; // These are for dynamicForm creation so leave it
_parmId =  element.args().parm(); // Getting the argument value from the Caller
//info(int2str(element.args().record().TableId));
if(!element.args().caller())   // Check the form is called by caller or directly, if directly it throw error
throw error(“Cant Run Directly”);
if(element.args().record().TableId == tablenum(EmplTable))   // check if the sent Table and the Current form table are equal or not
{
//        _EmplTable = element.args().record();  // Assign the Received Table name to Local Variable
//_dictTable = new DictTable(element.args().record().TableId);  // leave it , is used for Dynamic Form Creation
//_ds = form.addDataSource(_dictTable.name());  // leave it , is used for Dynamic Form Creation
//_ds.table(_dictTable.id());   // leave it , is used for Dynamic Form Creation
//frmGrid = form.addControl(FormControlType::Grid, “Grid”);   // leave it , is used for Dynamic Form Creation
//frmGrid.dataSource(_ds.name());   // leave it , is used for Dynamic Form Creation
//info(strfmt(“%1     %2″,_EmplTable.EmplId,_EmplTable.DEL_Name));
//frmGrid.addDataField(_ds.id(),fieldnum(EmplTable, DEL_Name));  // leave it , is used for Dynamic Form Creation
//        EmplTable_EmplId.dataSource(_EmplTable);   // leave it , is used for Dynamic Form Creation
//        EmplTable_EmplId.dataField(fieldnum(EmplTable,EmplID));   // leave it , is used for Dynamic Form Creation
//        EmplTable_DEL_Name.dataSource(_EmplTable);   // leave it , is used for Dynamic Form Creation
//        EmplTable_DEL_Name.dataField(fieldnum(EmplTable,EmplId));  // leave it , is used for Dynamic Form Creation
//        EmplTable_DEL_Email.dataSource(_EmplTable);   // leave it , is used for Dynamic Form Creation
//        EmplTable_DEL_Email.dataField(fieldnum(EmplTable,EmplId));   // leave it , is used for Dynamic Form Creation
super();  // Form Initialization
}
else
{
info(“DataSet Not Received”);  // throw error
}
}
11)Override the Init() of the DataSource
public void init()
{
switch(element.args().dataset())// get the table id sent by caller
{
case tablenum(EmplTable):  // check the table if matches with this tableid
{
_EmplID  =   element.args().parm();  // get the argument value
query   = new Query();            queryBuildRangeProj =                                          query.addDataSource(tablenum(EmplTable)).addRange(fieldnum(EmplTable,EmplId));          // query build for the form to display
queryBuildRangeProj.value(_emplId); // Criteria for the form
EmplTable_ds.query(query); // execution of the query
break;
}
}
super(); //datasource  initialization on the form based on the criteria
}
12) Save it, and create two menu items for each.
13) It is important to change the runon property of the FormB as CalledFrom.
14)Run the FormA and select an Employee Record and click the button.
15)The FormB opens with the Related information of the Selected Employee on form.


===========================================================================


Passing values between forms







For passing parameters from one form to another a special class Args is usually used.

Example:

The code of button click event of FormA which calls FormB and passes some parameters to that form.
void clicked()
{
// Args class is usually used in Axapta for passing parameters between forms
Args args;
FormRun formRun;
// Our custom made class for passing complex set of parameters
FormBParams formBParams = new FormBParams();
Array items = new Array( Types::String );
int i;
 ;

args = new args();

// Our values which we want to pass to FormB
// If we want pass just simple string we can use 'parm' method of 'Args' class
args.parm( strValue.text() );
// We also can pass enum value to FormB
args.parmEnum( NoYesEnumValue.selection() );
args.parmEnumType( EnumNum( NoYes ) );
// and also can pass a cursor pointing to some record (in our case it is EmplTable )
args.record( EmplTable );

// If we want pass more complex set of parameters we can develop our own class
// just for passing our parameters.
formBParams.parmSomeDate( someDate.dateValue() );
formBParams.parmSomeTime( someTime.value() );
for( i=0; i<ListBox.items(); i++ )
{
items.value( i+1, ListBox.getText( i ) );
}
formBParams.parmItems( items );
// Pass our object to FormB
args.parmObject( formBParams );

// Run FormB
args.name( formstr( FormB ) );
formRun = classFactory.formRunClass( Args );
formRun.init();
formrun.run();
formrun.wait();

if( formrun.closedOk() )
{
answerFromFormB.text( args.parm() );
}
super();
}

The code of init method of FormB
public void init()
{
EmplTable emplTableRecord;
FormBParams formBParams;
Array items;
int i;
 ;
super();

// Check for passed arguments
if( element.args() )
{
// get string parameter
strValue.text( element.args().parm() );

// get enum parameter
if( element.args().parmEnumType() == EnumNum( NoYes ) )
{
NoYesEnumValue.selection( element.args().parmEnum() );
}
// get object parameter
if( element.args().parmObject() )
{
formBParams = element.args().parmObject();
items = formBParams.parmItems();
for( i=1; i<=items.lastIndex(); i++ )
{
ListBox.add( items.value(i) );
}
someDate.dateValue( formBParams.parmSomeDate() );
someTime.value( formBParams.parmSomeTime() );
}
// get record parameter
if( element.args().record() && element.args().record().TableId == TableNum( EmplTable ) )
{
emplTableRecord = element.args().record();
emplName.text( emplTableRecord.Name );
}
}
}

The code of ok button click event of FromB
void clicked()
{
super();
element.args().parm( strAnswer.text() );
element.closeOk();
}

The above code is cut out from a demo which you can download here.




===========================================================================



For passing parameters from one form to another a special class Args is usually used.

Example:

The code of button click event of FormA which calls FormB and passes some parameters to that form.
void clicked()
{
// Args class is usually used in Axapta for passing parameters between forms
Args args;
FormRun formRun;
// Our custom made class for passing complex set of parameters
FormBParams formBParams = new FormBParams();
Array items = new Array( Types::String );
int i;
 ;

args = new args();

// Our values which we want to pass to FormB
// If we want pass just simple string we can use 'parm' method of 'Args' class
args.parm( strValue.text() );
// We also can pass enum value to FormB
args.parmEnum( NoYesEnumValue.selection() );
args.parmEnumType( EnumNum( NoYes ) );
// and also can pass a cursor pointing to some record (in our case it is EmplTable )
args.record( EmplTable );

// If we want pass more complex set of parameters we can develop our own class
// just for passing our parameters.
formBParams.parmSomeDate( someDate.dateValue() );
formBParams.parmSomeTime( someTime.value() );
for( i=0; i<ListBox.items(); i++ )
{
items.value( i+1, ListBox.getText( i ) );
}
formBParams.parmItems( items );
// Pass our object to FormB
args.parmObject( formBParams );

// Run FormB
args.name( formstr( FormB ) );
formRun = classFactory.formRunClass( Args );
formRun.init();
formrun.run();
formrun.wait();

if( formrun.closedOk() )
{
answerFromFormB.text( args.parm() );
}
super();
}

The code of init method of FormB
public void init()
{
EmplTable emplTableRecord;
FormBParams formBParams;
Array items;
int i;
 ;
super();

// Check for passed arguments
if( element.args() )
{
// get string parameter
strValue.text( element.args().parm() );

// get enum parameter
if( element.args().parmEnumType() == EnumNum( NoYes ) )
{
NoYesEnumValue.selection( element.args().parmEnum() );
}
// get object parameter
if( element.args().parmObject() )
{
formBParams = element.args().parmObject();
items = formBParams.parmItems();
for( i=1; i<=items.lastIndex(); i++ )
{
ListBox.add( items.value(i) );
}
someDate.dateValue( formBParams.parmSomeDate() );
someTime.value( formBParams.parmSomeTime() );
}
// get record parameter
if( element.args().record() && element.args().record().TableId == TableNum( EmplTable ) )
{
emplTableRecord = element.args().record();
emplName.text( emplTableRecord.Name );
}
}
}

The code of ok button click event of FromB
void clicked()
{
super();
element.args().parm( strAnswer.text() );
element.closeOk();
}

 





Passing Parameters to a Report in Dynamics AX

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;
;

args.parm(PurchReqTable.PurchReqId);

args.name(reportstr(PurchRequisitionDetails));
reportRun = classFactory.reportRunClass(args);
reportRun.init();
reportrun.run();
//hello

super();
}

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()
{
;
try
{
if(element.args().parm())
{
this.query().dataSourceTable(tablenum(PurchReqTable))
.addRange(fieldnum(PurchReqTable, PurchReqId)).value(element.args().parm());

this.query().userUpdate(false);
this.query().interactive(false);
super();
}
}

catch(exception::Error)
{
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.


Pass The Parameters to Class

To pass the parameter from the form selected record to class


1.Create a class as following code.
2.Add this class to Actions MenuItem.
3.In form add this MenuItemButton.
Open the form Select a record in the grid and click the button.
That record passed to the Main method. in info you will Vendor id get 2 times.
Cause New Method is calling and Post method is calling. 

public class EmplProcess
{
VendTable _VendTable;
}
-
public void new(Common vTable)
{
_VendTable = vTable;
this.post();
}
-
public void post()
{
info(_VendTable.AccountNum);
}
-
public static void main(Args args)
{
Common _common;
EmplProcess _EmplProcess;

_common = args.record(); //getting the record from the form
_EmplProcess = new EmplProcess(_common);//passing the above record to the new method
_EmplProcess.post();// calling the post method
}
__________________________________________________________________________________–

While creating Object for class we can pass the parameter.
ex:

Class1 cls;
;
cls = new Class(VendTable);// this is Data Source name in Vend Table form

//in class override the new method and assign the Parameter.
public void new(VendTable vTable)
{
_VendTable = vTable;
}

Wednesday, 6 February 2013

Types of Form Templates in AX 2012

Types of Form Templates in AX 2012:

Untitled

There are seven different predefined form templates in ax 2012.

  • ListPage

  • DetailsFormMaster

  • DetailsFormTransaction

  • SimpleListDetails

  • SimpleList

  • TableOfContents

  • Dialog

  • DropDialog


ListPage - A list page is a form that displays a list of data related to a particular entity or business object. A list page provides provisions for displaying data and taking actions on this data. Every module has at least a couple of list pages. List pages are further classified as primary and secondary list pages. A secondary list page will only display a subset of data from the primary list page. Example, CustTableListPage, VendTableListPage, ProjProjectsListPage. Best practice is to have ListPage as a suffix in the name of the form for all list pages.

 

DetailsFormMaster: This template is used for forms which display data for stand-alone entities or business objects. Example includes Customers, Vendors, and Projects etc. If you look at the forms for these, i.e. CustTable, VendTable, ProjTable, their style property will be set to DetailsFormMaster.

DetailsFormTransaction: This template is used for forms which display data for entities which have child records associated with it. In other words, if the data being displayed is header-lines type in nature, use this template. Example, Sales orders, Purchase orders etc. If you look at the style property of SalesTable, VendTable, their properties will be set to DetailsFormTransaction.

SimpleListDetails - This template is used to display primary fields in a list and detailed data in a tab page. This style is useful to view all records in a form and selecting a particular record will bring up their details. Example includes HmSkillMapping, etc.

SimpleList - This template is a very basic form which displays data in a grid. No extra or fancy detail is displayed. This style is best suited for forms where data being shown is not very detailed in nature or has limited fields. Example includes AifAction, etc.

TableOfContents - This template is the new style which should be adopted for all parameter forms in Dynamics AX 2012. Take a look at any parameters form and its style property will be set to TableOfContents. This style sets all the tabs as a hot link in the left hand side navigation pane. Clicking on the link will bring up the controls on that tab page. This style is a very neat and appealing UI design which is surely welcome. Example includes Custparameters, vendparameters, etc.

Dialog - This template is used on forms which show static data or are intended to capture some user input for further actions. These forms are mostly modal in nature and should be dismissed before any further actions can be taken.

DropDialog - This template is used for forms that are used to gather quick user inputs to perform an action. Drop dialog forms are generally attached to an action pane button. They appear to be             dropping from the menu button when clicked. Example includes HcmWorkerNewWorker,                                                               HcmPositionWorkerAssignmentDialog

 

Whenever going for a new form development, always ensure that you use the template to create a new form. The template almost does 40% of your design work for you. All you have to do is add the data sources and fields and add business logic.

Microsoft has taken a lot of customer feedback and invested a lot in the UI design. There are reasons why the buttons and navigations are laid out like they are. If you are deviating from the recommended best practices, not only are you introducing best practice deviations, you may be complicating the design and navigation for your users.

In case, you already have designed forms without using the pre-defined templates, you can run the form style best practices checker from add-ins. This will list out all deviations your form has and you can fix them by clicking a button.

 

 

Check form Style Best practices:

Untitled1

The form will be open to show all the violation, also there is button to auto fix those violation, some of them you need to fix it manually.