Friday, May 14, 2010

Sending Fax from AX

Sending Fax from AX is common requirement.
This can be achieved in following way

Use the Com class wrapper wizard and load the Microsoft Fax Service

MFSFaxDocument MFSFaxDocument ;
;
MFSFaxDocument = new MFSFaxDocument();
MFSFaxDocument .Body('C:\\Matrish.txt');
MFSFaxDocument .Recipients().Add('Faxno','Receiver Name');
MFSFaxDocument .Subject('Test Fax');
MFSFaxDocument .Sender().Name('Sender Name');
MFSFaxDocument .Submit('ServerName');

Adding Find\Filter functionality on Display method

Adding Find\Filter functionality on Display method

Override Context method of Form control which is using display method and provide code for filter. E.g I have done below for PhysicalInvent field of InventOnHandItem form.

void context()
{

int selectedMenu;
real test;
formrun fr;
Args ag;
Itemname strtext;
querybuilddataSource qb1;
queryrun qr;
query q;
PopupMenu menu = new PopupMenu(element.hWnd());
int a = menu.insertItem('Find');
int b = menu.insertItem('Filter');
int c = menu.insertItem('Remove Filter');


selectedMenu = menu.draw();

switch (selectedMenu)
{
case -1:
break;

case a:
ag = new args('SysformSearch');
fr = new formrun(ag);
fr.run();
fr.wait();
strtext = fr.design().controlName('FindEdit').valueStr();
if(strtext)
{
q = inventSum_Ds.query();
qb1 =q.dataSourceTable(tablenum(InventSum));
QB1.addRange(FieldNum(InventSum,PhysicalInvent)).value(SySQuery::value(strtext));
INVENTSUM_DS.query(Q);
INVENTSUM_ds.executeQuery();
}
break;

case b:
InventSum_DS.filter(FieldNum(InventSum,PhysicalInvent),Sysquery::value(InventSum.PhysicalInvent()));
break;

case c :
InventSum_DS.removeFilter();
break;

Default:
break;
}

}

Prevent a form from closing

Override canClose method of that form, and call winAPI::minimizeWindow, when
the form cannot be closed.
This is the sample code, but require new checkBox control (named
"okToClose") with "autoDeclare" property is "Yes":


public boolean canClose()
{
boolean ret;
ret = super();
if (okToClose.value() == NoYes::Yes)
{
ret = true;
}
else
{
ret = false;
WinAPI::minimizeWindow(element.hWnd());
}
return ret;
}

Reserving inventory by code

Reserving inventory by code


static void ReserveQty(Args _args)
{
SalesLine SalesLine = SalesLine::findRecId(35522);
InventDim InventDim = SalesLine.inventDim();
InventUpd_Reservation reservation;
;
reservation = InventUpd_Reservation::newMovement(InventMovement::construct(SalesLine,true,inventDim),-5,true);
reservation.updateNow();

}

Code to add EDT of through X++ code

static void Job19(Args _args)
{
UtilIdElements uie;
XInfo XInfo = new XInfo();
TreeNode TNode;
TreeNode DNode;

str Props =
"PROPERTIES\n" +
" Name #AXUStr35\n" +
" Label #\n" +
" HelpText #\n" +
" FormHelp #\n" +
" ArrayLength #1\n" +
" DisplayLength #Auto\n" +
" ConfigurationKey #\n" +
" ButtonImage #Arrow\n" +
" Extends #\n" +
" DisplayHeight #Auto\n" +
" StringSize #35\n" +
" Adjustment #Left\n" +
" Alignment #Auto\n" +
" ChangeCase #Auto\n" +
"ENDPROPERTIES\n";

select maxof(id) from uie where uie.recordType ==
UtilElementType::ExtendedType && uie.utilLevel == XInfo.currentAOLayer();

uie.id++;
uie.utilLevel = XInfo.currentAOLayer();
uie.recordType = UtilElementType::ExtendedType;
uie.name = "AXUStr35";

uie.insert();
DNode = TreeNode::findNode("Data Dictionary\\Extended Data Types");
DNode.AOTrefresh();

TNode = TreeNode::findNode("Data Dictionary\\Extended Data Types\\AXUStr35");
TNode.sysUtilDelete();

TNode.AOTsetProperties(Props);
TNode.AOTsave();

// pause;


}

Code to add EDT of through X++ code

static void Job19(Args _args)
{
UtilIdElements uie;
XInfo XInfo = new XInfo();
TreeNode TNode;
TreeNode DNode;

str Props =
"PROPERTIES\n" +
" Name #AXUStr35\n" +
" Label #\n" +
" HelpText #\n" +
" FormHelp #\n" +
" ArrayLength #1\n" +
" DisplayLength #Auto\n" +
" ConfigurationKey #\n" +
" ButtonImage #Arrow\n" +
" Extends #\n" +
" DisplayHeight #Auto\n" +
" StringSize #35\n" +
" Adjustment #Left\n" +
" Alignment #Auto\n" +
" ChangeCase #Auto\n" +
"ENDPROPERTIES\n";

select maxof(id) from uie where uie.recordType ==
UtilElementType::ExtendedType && uie.utilLevel == XInfo.currentAOLayer();

uie.id++;
uie.utilLevel = XInfo.currentAOLayer();
uie.recordType = UtilElementType::ExtendedType;
uie.name = "AXUStr35";

uie.insert();
DNode = TreeNode::findNode("Data Dictionary\\Extended Data Types");
DNode.AOTrefresh();

TNode = TreeNode::findNode("Data Dictionary\\Extended Data Types\\AXUStr35");
TNode.sysUtilDelete();

TNode.AOTsetProperties(Props);
TNode.AOTsave();

// pause;


}

Code for Displaying Back Ground Colour on the basis of Record

*******This Code is use for DisPlay Back Ground Colour on the basis of
Record
----------------------------------------------------------------------
(1) ##### this is for decaration in foms's ClasssDeclaration
for the perpose of Colour the record.

public class FormRun extends ObjectRun
{
int principal;
int nonPrincipal ;
}

(2)##### this is for the purpose of initializing colour of that perticular
record. this code is written on Forms's Init().
public void init()
{
principal = winapi::RGB2int(192,192,192);
nonPrincipal = winapi::RGB2int(255,255,255);
super();
}

(3)#### this is written on DataSource.

public void displayOption(Common _record, FormRowDisplayOption _options)
{
;
spnSizesEuivalances = _record;
if(spnsizeGroups::findPrincipal(spnSizesEuivalances.SizeGroups).PrincipalGrp)
_options.backColor(principal);
else
_options.backColor(nonPrincipal);
}

Simple code for getting Onhand of item

Here is simple code for getting onhand inventory of some item on specific inventory dimension.

static void InventOnHand(Args _args)
{
InventDimParm InventDimParm;
InventSum InventSum;
InventDim InventDim;
;
InventDim.inventBatchId = '';
InventDim.InventSizeId = '';
InventDim.InventLocationId = '';
InventDimParm.initFromInventDim(InventDim);
InventSum = InventSum::findSum('',InventDim,inventDimParm);
InventSum.availPhysical();
}

Monday, April 26, 2010

The Year of the Cloud: How Coming Microsoft Products Will Make Dynamics AX the Basis of New Solutions

Good article on cloud

Dynamics AX and cloud

New certification on Microsoft Dynamics

Managing Microsoft Dynamics Implementations Certification Exam (Prometric Exam # MB5-858) Preparation Guide

Microsoft Dynamics Implementations Certification Exam Preparation guide

Keep learning :-)

Dynamics AX 6.0 Deployment Engine

Another good link on Dynamics AX 6.0.

Dynamics AX 6.0 Deployment Engine

Thanks Dilip for such a nice post..:-)

New changes in Dynamics AX 6.0

Just now while surfing I found a blog which is talking about changes in Dynamics AX 6.0(2011) editor... Attaching the link....

Changes in Dynamics AX 6.0 editor

good to see this ....

Saturday, April 24, 2010

Preventing AX form to close

Friends although its very small thing and many of you might have done this multiple time but thought to put it here so that it can be useful for others. :-)

Override canClose method of that form, and call winAPI::minimizeWindow, whenthe form cannot be closed.

This is the sample code, but require new checkBox control (named"okToClose") with "autoDeclare" property is "Yes":

public boolean canClose()
{
boolean ret;
ret = super();
if (okToClose.value() == NoYes::Yes)
{
ret = true;
}
else
{
ret = false;
WinAPI::minimizeWindow(element.hWnd());
}
return ret;
}

Expressions in query ranges (From Axaptapedia)

Introduction
This is a method of specifying ranges on queries which allows you to perform complex comparisons, and create complex join situations which would be impossible using the standard syntax.
Syntax
To use the special syntax, you should first add a range to your QueryBuildDataSource object in the normal way. Note that for this special syntax, it does not matter which field you use to add the range.
To specify the range value itself, certain rules must be followed:
• The entire expression must be enclosed within single-quotes, not double-quotes
• The entire expression must be enclosed in parenthesis (brackets)
• Each sub-expression must be enclosed in its own set of parenthesis
• For fields in the current table, simply the field name can be used
• For fields in other tables, a prefix of the relevant datasource name must be added. This is not always the same as the table name.
• String values should be surrounded by double-quotes, and wrapped in a call to queryValue()
• Enum values should be specified by their integer value
• Date values should be formatted using Date2StrXpp()
Examples
In the example below, we construct a query and add a single datasource.
The range is then added, using the DataAreaId field on each table. Any field can be used, but using an unusual one such as DataAreaId helps remind a casual reader of the code that it's not a normal range.
query = new Query();
dsInventTable = query.addDataSource(tableNum(InventTable));

// Add our range
queryBuildRange = dsInventTable.addRange(fieldNum(InventTable, DataAreaId));
Given the above, the following are valid range specifications:
Simple criteria
Find the record where ItemId is B-R14. Take note of the single quotes and parenthesis surrounding the entire expression.
queryBuildRange.value(strFmt('(ItemId == "%1")', queryValue("B-R14")));
Find records where the ItemType is Service. Note the use of any2int().
queryBuildRange.value(strFmt('(ItemType == %1)', any2int(ItemType::Service)));
Find records where the ItemType is Service or the ItemId is B-R14. Note the nesting of the parenthesis in this example.
queryBuildRange.value(strFmt('((ItemType == %1) (ItemId == "%2"))',
any2int(ItemType::Service),
queryValue("B-R14")));
Find records where the modified date is after 1st January 2000. Note the use of Date2StrXpp() to format the date correctly.
queryBuildRange.value(strFmt('(ModifiedDate > %1)', Date2StrXpp(01012000)));
Complex criteria with combined AND and OR clauses
Find all records where the ItemType is Service, or both the ItemType is Item and the ProjCategoryId is Spares. This is not possible to achieve using the standard range syntax.
Note also that in this example, we are using the fieldStr() method to specify our actual field names and again, that we have nested our parenthesis for each sub-expression.
queryBuildRange.value(strFmt('((%1 == %2) ((%1 == %3) && (%4 == "%5")))',
fieldStr(InventTable, ItemType),
any2int(ItemType::Service),
any2int(ItemType::Item),
fieldStr(InventTable, ProjCategoryId),
queryValue("Spares")));
WHERE clauses referencing fields from multiple tables
For this example below, we construct a query consisting of two joined datasources (using an Exists join). Note that we specify the datasource names when adding the datasources to the query.
The ranges are then added, using the DataAreaId field on each table as described in the earlier example.
query = new Query();
dsInventTable = query.addDataSource(tableNum(InventTable), tableStr(InventTable));
dsInventItemBarCode = dsInventTable.addDataSource(tableNum(InventItemBarCode), tableStr(InventItemBarCode));
dsInventItemBarCode.relations(true);
dsInventItemBarCode.joinMode(JoinMode::ExistsJoin);

// Add our two ranges
queryBuildRange1 = dsInventTable.addRange(fieldNum(InventTable, DataAreaId));
queryBuildRange2 = dsInventItemBarCode.addRange(fieldNum(InventItemBarCode, DataAreaId));
Find all records where a bar code record exists for an item and was modified later than the item was modified.
In this example, we are using the range on the BarCode table. Therefore the unqualified ModifiedDate reference will relate to InventItemBarCode.ModifiedDate. The other field is a fully-qualified one, using the DatasourceName.FieldName syntax.
queryBuildRange2.value(strFmt('(ModifiedDate > InventTable.ModifiedDate)'));
Note that if we had added our InventTable datasource using the following code
dsInventTable = query.addDataSource(tableNum(InventTable), "InventTableCustomName"); // Note that we are manually specifying a different datasource name
then the query range would need to appear as follows
queryBuildRange2.value(strFmt('(ModifiedDate > InventTableCustomName.ModifiedDate)'));
Conditional joins
We will modify our previous example slightly, to remove the automatic addition of relations for the join.
query = new Query();
dsInventTable = query.addDataSource(tableNum(InventTable), "InventTable");
dsInventItemBarCode = dsInventTable.addDataSource(tableNum(InventItemBarCode), "InventItemBarCode");
dsInventItemBarCode.joinMode(JoinMode::ExistsJoin);

// Add our two ranges
queryBuildRange1 = dsInventTable.addRange(fieldNum(InventTable, DataAreaId));
queryBuildRange2 = dsInventItemBarCode.addRange(fieldNum(InventItemBarCode, DataAreaId));
We can now use the query expression to specify whatever we like as the join criteria.
Find all records where either the ItemType is Service, or the ItemType is Item and a barcode exists. The join criteria is only applied in the second half of the expression, so all Service items will appear irrespective of whether they have a bar code. Again, this is not possible to achieve using the standard query ranges.
queryBuildRange2.value(strFmt('((%1.%2 == %3) ((%1.%2 == %4) && (%1.%5 == %6)))',
query.dataSourceTable(tableNum(InventTable)).name(), // InventTable %1
fieldStr(InventTable, ItemType), // ItemType %2
any2int(ItemType::Service), // %3
any2int(ItemType::Item), // %4
fieldStr(InventTable, ItemId), // ItemId %5
fieldStr(InventItemBarCode, ItemId))); // %6
Using the techniques above, it is possible to create queries with almost as much flexibility as using SQL statements directly.
Limitations
There are two major limitations to the Query Expressions syntax. The first is the loss of support for wildcards and comma-separated range values, and the second is the inability to reference array fields such as dimensions.