Report->Fetch method
public boolean fetch()
{
boolean ret;
CustTable custTable;
;
// ret = super();
while select crosscompany custTable
{
this.send(custTable);
}
return true;
}
This blog is for Dynamics AX (AXAPTA) Developers,this will help you for your development issues. This site contains some Microsoft Dynamics AX X++ Codes for use in your day to day use.
29 October 2010
27 October 2010
pass the parameter to report in Dynamics AX
1. Calling menuItem. Task
This is in Report to get selected record parameter like sales id ,this code is making the defalut range value the selected record of S.O -> salesId. this will pront the selected record only on report
Here we are controlling the query range prompt.
Sales Tabel form -> MenuItembutton clicked()- properties remove the menuItemName:
void clicked()
{
Args args = new Args();
MenuFunction menuFunction;
;
args.parm(SalesTable.SalesId);
menuFunction = new MenuFunction(menuitemoutputstr(Report9), MenuItemType::Output);// Report9 is menuItem
menuFunction.run(args);
super();
}
--------
In Report-> init()
public void init()
{
try
{
if(element.args().parm())
{
this.query().dataSourceTable(tablenum(SalesTable)).addRange(fieldnum(SalesTable,SalesId)).value(element.args().parm());
salesId = element.args().parm();
this.query().userUpdate(false);
this.query().interactive(false);
super();
}
}
catch(exception::Error)
{
info("Errosr in init");
}
}
-----------------------------------------------
2.calling report
form->Button
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();
}
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”);
}
}
This is in Report to get selected record parameter like sales id ,this code is making the defalut range value the selected record of S.O -> salesId. this will pront the selected record only on report
Here we are controlling the query range prompt.
Sales Tabel form -> MenuItembutton clicked()- properties remove the menuItemName:
void clicked()
{
Args args = new Args();
MenuFunction menuFunction;
;
args.parm(SalesTable.SalesId);
menuFunction = new MenuFunction(menuitemoutputstr(Report9), MenuItemType::Output);// Report9 is menuItem
menuFunction.run(args);
super();
}
--------
In Report-> init()
public void init()
{
try
{
if(element.args().parm())
{
this.query().dataSourceTable(tablenum(SalesTable)).addRange(fieldnum(SalesTable,SalesId)).value(element.args().parm());
salesId = element.args().parm();
this.query().userUpdate(false);
this.query().interactive(false);
super();
}
}
catch(exception::Error)
{
info("Errosr in init");
}
}
-----------------------------------------------
2.calling report
form->Button
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();
}
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”);
}
}
25 October 2010
Storing Last Form Values
Dynamics AX has a very useful feature, which allows saving the latest user choices per user per form. This feature is implemented across a number of standard reports, periodic jobs, and other objects, which require user input.
In this recipe, we will see how to store the latest user filter selections. To make it as simple as possible, we will use existing filters on the General journal form, which can be opened from General ledger | Journals | General journal. This form contains two filters—Show and Show user-created only. Show allows displaying journals by their posting status and Show user-created only toggles between all journals and the currently logged user's journals.
1.Find the LedgerJournalTable form in AOT, and add the following code to the bottom of its class declaration:
AllOpenPosted showStatus;
NoYes showCurrentUser;
#define.CurrentVersion(1)
#localmacro.CurrentList
showStatus,
showCurrentUser
#endmacro
------------------------------------------------
2.Create these additional form methods:
public void initParmDefault()
{
;
showStatus = AllOpenPosted::Open;
showCurrentUser = true;
}
public container pack()
{
return [#CurrentVersion,#CurrentList];
}
-----------------------------------------------------------
public boolean unpack(container packedClass)
{
int version = RunBase::getVersion(packedClass);
;
switch (version)
{
case #CurrentVersion:[version,#CurrentList] = packedClass;
return true;
default:
return false;
}
return false;
}
------------------------------------------
public identifiername lastValueDesignName()
{
return element.args().menuItemName();
}
------------------------------------------
public identifiername lastValueElementName()
{
return this.name();
}
----------------------------------------
public UtilElementType lastValueType()
{
return UtilElementType::Form;
}
----------------------------------------
public userId lastValueUserId()
{
return curuserid();
}
----------------------------------------
public dataAreaId lastValueDataAreaId()
{
return curext();
}
In this recipe, we will see how to store the latest user filter selections. To make it as simple as possible, we will use existing filters on the General journal form, which can be opened from General ledger | Journals | General journal. This form contains two filters—Show and Show user-created only. Show allows displaying journals by their posting status and Show user-created only toggles between all journals and the currently logged user's journals.
1.Find the LedgerJournalTable form in AOT, and add the following code to the bottom of its class declaration:
AllOpenPosted showStatus;
NoYes showCurrentUser;
#define.CurrentVersion(1)
#localmacro.CurrentList
showStatus,
showCurrentUser
#endmacro
------------------------------------------------
2.Create these additional form methods:
public void initParmDefault()
{
;
showStatus = AllOpenPosted::Open;
showCurrentUser = true;
}
public container pack()
{
return [#CurrentVersion,#CurrentList];
}
-----------------------------------------------------------
public boolean unpack(container packedClass)
{
int version = RunBase::getVersion(packedClass);
;
switch (version)
{
case #CurrentVersion:[version,#CurrentList] = packedClass;
return true;
default:
return false;
}
return false;
}
------------------------------------------
public identifiername lastValueDesignName()
{
return element.args().menuItemName();
}
------------------------------------------
public identifiername lastValueElementName()
{
return this.name();
}
----------------------------------------
public UtilElementType lastValueType()
{
return UtilElementType::Form;
}
----------------------------------------
public userId lastValueUserId()
{
return curuserid();
}
----------------------------------------
public dataAreaId lastValueDataAreaId()
{
return curext();
}
21 October 2010
create a new Table by using a X++ code
static void newTableCreate(Args _args)
{
TreeNode treeNode;
#AOT
;
treeNode = TreeNode::findNode(#TablesPath);
treeNode.AOTadd("Table_Test");
SqlDataDictionary::synchronize();
}
{
TreeNode treeNode;
#AOT
;
treeNode = TreeNode::findNode(#TablesPath);
treeNode.AOTadd("Table_Test");
SqlDataDictionary::synchronize();
}
18 October 2010
Created EDT with code
static void EDT_By_Code(Args _args)
{
AOTTableFieldList aTFL;
AOTTableFieldList aEDTL;
TreeNode fieldNode;
Types _enum = Types::String;
str property;
;
aEDTL = infolog.findNode('\\Data Dictionary\\Extended Data Types');
if (!aEDTL.AOTFindChild('test'))
{
aEDTL.AOTaddExtendedDataType('test', _enum);
fieldNode = aEDTL.AOTFindChild('test');
fieldNode.AOTsave();
}
property = setProperty(fieldnode.AOTgetProperties(), 'StringSize', '30');
fieldNode.AOTsave();
info(property);
fieldNode.AOTsetProperties(property);
fieldNode.AOTrefresh();
}
{
AOTTableFieldList aTFL;
AOTTableFieldList aEDTL;
TreeNode fieldNode;
Types _enum = Types::String;
str property;
;
aEDTL = infolog.findNode('\\Data Dictionary\\Extended Data Types');
if (!aEDTL.AOTFindChild('test'))
{
aEDTL.AOTaddExtendedDataType('test', _enum);
fieldNode = aEDTL.AOTFindChild('test');
fieldNode.AOTsave();
}
property = setProperty(fieldnode.AOTgetProperties(), 'StringSize', '30');
fieldNode.AOTsave();
info(property);
fieldNode.AOTsetProperties(property);
fieldNode.AOTrefresh();
}
08 October 2010
To add lookup in form control
we are adding Form control lookup Vend accountNum and Vend name
public void lookup()
{
SysTableLookup sysTableLookup;
VendTable vendTable;
;
sysTableLookup = SysTableLookup::newParameters(tablenum(VendTable), this);
sysTableLookup.addLookupfield(fieldnum(vendTable, AccountNum),true);
sysTableLookup.addLookupfield(fieldnum(vendTable, Name),true);
sysTableLookup.performFormLookup();
//super();
}
public void lookup()
{
SysTableLookup sysTableLookup;
VendTable vendTable;
;
sysTableLookup = SysTableLookup::newParameters(tablenum(VendTable), this);
sysTableLookup.addLookupfield(fieldnum(vendTable, AccountNum),true);
sysTableLookup.addLookupfield(fieldnum(vendTable, Name),true);
sysTableLookup.performFormLookup();
//super();
}
06 October 2010
WorkCalendarSched
When programming Dynamics AX it is very easy to add days to a date. You can take todays date and just add an integer of five to get the date five days from now. But because this is easy to do it doesn’t mean that this always is the right way to go about this date business.
If you look closer at how the dates are calculated on the sales order lines or the purchase order lines in Dynamics AX you see that a class called WorkCalendarSched is used. This is because deliveries are dependant on when the company using Dynamics AX actually can send the order. Not all companies work on weekends.
This is when WorkCalendarSched comes in handy, with this class and the class method “shedDate” you can make sure that the delivery is set to a day when the company actually is going to be able deliver.
This is a basic job that uses the class WorkCalendarSched and the method “shedDate”:
static void FO_stepCalendar(Args _args)
{
SchedDate schedDate;
date fromDate = systemDateGet(),
testDate;
WorkCalendarSched workCalendarSched;
int days2step = 4;
boolean calendarDays = false;
CustTable cust = CustTable::find("4000");
;
// Without using schedDate.
testDate = fromDate + days2step;
workCalendarSched = new WorkCalendarSched();
schedDate = workCalendarSched.schedDate(
SchedDirection::Forward,
fromDate,
days2step,
calendarDays,
cust.SalesCalendarId,
CompanyInfo::find().ShippingCalendarId);
print strFmt("From date: %1", fromDate);
print strFmt("Test date: %1", testDate);
print strFmt("Scheddate: %1", schedDate);
print strFmt("%1", workCalendarSched.isDateOpen(
CompanyInfo::find().ShippingCalendarId,
testDate));
print strFmt("%1", workCalendarSched.isDateOpen(
CompanyInfo::find().ShippingCalendarId,
schedDate));
pause;
}
If you look closer at how the dates are calculated on the sales order lines or the purchase order lines in Dynamics AX you see that a class called WorkCalendarSched is used. This is because deliveries are dependant on when the company using Dynamics AX actually can send the order. Not all companies work on weekends.
This is when WorkCalendarSched comes in handy, with this class and the class method “shedDate” you can make sure that the delivery is set to a day when the company actually is going to be able deliver.
This is a basic job that uses the class WorkCalendarSched and the method “shedDate”:
static void FO_stepCalendar(Args _args)
{
SchedDate schedDate;
date fromDate = systemDateGet(),
testDate;
WorkCalendarSched workCalendarSched;
int days2step = 4;
boolean calendarDays = false;
CustTable cust = CustTable::find("4000");
;
// Without using schedDate.
testDate = fromDate + days2step;
workCalendarSched = new WorkCalendarSched();
schedDate = workCalendarSched.schedDate(
SchedDirection::Forward,
fromDate,
days2step,
calendarDays,
cust.SalesCalendarId,
CompanyInfo::find().ShippingCalendarId);
print strFmt("From date: %1", fromDate);
print strFmt("Test date: %1", testDate);
print strFmt("Scheddate: %1", schedDate);
print strFmt("%1", workCalendarSched.isDateOpen(
CompanyInfo::find().ShippingCalendarId,
testDate));
print strFmt("%1", workCalendarSched.isDateOpen(
CompanyInfo::find().ShippingCalendarId,
schedDate));
pause;
}
Strange behaviour when calling form
I was building an extended search form for one of our customers. When called from one form everything worked fine, but when called from a second form my grid only contained one record… Exact same parameters, same menu item etc. When looking around I found that when the error occured, I was calling from a form which had same table (InventTable) as one of it’s main Data Sources. This is one of the non-documented features in AX, if same table exists in the Data Sources in both forms, AX tryes to link them together. To break this connection I had to call ClearDynaLinks() on the second form. Like below, in my search form’s init method.
void init()
{
....
InventTable_ds.query().dataSourceTable(
tablenum(InventTable)).clearDynalinks();
}
void init()
{
....
InventTable_ds.query().dataSourceTable(
tablenum(InventTable)).clearDynalinks();
}
Jump between InterCompany order lines
This is a basic job that describes how you can jump from one order line to another in the intercompany order structure.
In this example I have created an intercompany order that also has a linked purchase order in the production company to a vendor. This is one way you can use to jump up between the linked order lines.
I start out in the sales company “FO1” and go all the way up to the intercompany sales line in the production company “FO”, then I change company to “FO” so that I can gain access to the production company’s purchase line. From this purchase line I change the direction and move all the way back to the original sales line that is located in the sales company FO1.
As you can see I run the code while being in the sales company “FO1″. I start out with a specific sales line that I get by searching for its RecId. This code it meant to be run with a sales line as its basis. Preferably from the SalesTable form, the SalesLine table or some other object where you have sales line data that you want to explore.
static void FO_InterCompanyRefs(Args _args)
{
SalesLine salesLine =
SalesLine::findRecId(5637552101),
icSalesLine = null;
PurchLine purchLine,
icPurchLine;
;
// Sales company = FO1
// Production company = FO
// Original Sales Company SalesLine
print salesLine.SalesId;
print salesLine.ItemId;
print salesLine.dataAreaId;
print "------------------";
purchLine =
PurchLine::findInventTransId(
salesLine.InventRefTransId);
// Sales Company PurchLine
print purchLine.PurchId;
print purchLine.ItemId;
print purchLine.dataAreaId;
print "------------------";
icSalesLine =
purchLine.interCompanySalesLine();
// Production company SalesLine
print icSalesLine.SalesId;
print icSalesLine.ItemId;
print icSalesLine.dataAreaId;
print "------------------";
changecompany(icSalesLine.dataAreaId)
{
purchLine = PurchLine::findInventTransId(
icSalesLine.InventRefTransId);
// Production company PurchLine
print purchLine.PurchId;
print purchLine.ItemId;
print purchLine.dataAreaId;
print "------------------";
icSalesLine =
SalesLine::findInventTransId(
purchLine.InventRefTransId);
// Production company SalesLine
print icSalesLine.SalesId;
print icSalesLine.ItemId;
print icSalesLine.dataAreaId;
print "------------------";
purchLine =
icSalesLine.interCompanyPurchLine();
// Sales Company PurchLine
print purchLine.PurchId;
print purchLine.ItemId;
print purchLine.dataAreaId;
print "------------------";
salesLine =
purchLine.interCompanySalesLineOriginal();
// Sales Company PurchLine
print salesLine.SalesId;
print salesLine.ItemId;
print salesLine.dataAreaId;
print "------------------";
}
pause;
}
In this example I have created an intercompany order that also has a linked purchase order in the production company to a vendor. This is one way you can use to jump up between the linked order lines.
I start out in the sales company “FO1” and go all the way up to the intercompany sales line in the production company “FO”, then I change company to “FO” so that I can gain access to the production company’s purchase line. From this purchase line I change the direction and move all the way back to the original sales line that is located in the sales company FO1.
As you can see I run the code while being in the sales company “FO1″. I start out with a specific sales line that I get by searching for its RecId. This code it meant to be run with a sales line as its basis. Preferably from the SalesTable form, the SalesLine table or some other object where you have sales line data that you want to explore.
static void FO_InterCompanyRefs(Args _args)
{
SalesLine salesLine =
SalesLine::findRecId(5637552101),
icSalesLine = null;
PurchLine purchLine,
icPurchLine;
;
// Sales company = FO1
// Production company = FO
// Original Sales Company SalesLine
print salesLine.SalesId;
print salesLine.ItemId;
print salesLine.dataAreaId;
print "------------------";
purchLine =
PurchLine::findInventTransId(
salesLine.InventRefTransId);
// Sales Company PurchLine
print purchLine.PurchId;
print purchLine.ItemId;
print purchLine.dataAreaId;
print "------------------";
icSalesLine =
purchLine.interCompanySalesLine();
// Production company SalesLine
print icSalesLine.SalesId;
print icSalesLine.ItemId;
print icSalesLine.dataAreaId;
print "------------------";
changecompany(icSalesLine.dataAreaId)
{
purchLine = PurchLine::findInventTransId(
icSalesLine.InventRefTransId);
// Production company PurchLine
print purchLine.PurchId;
print purchLine.ItemId;
print purchLine.dataAreaId;
print "------------------";
icSalesLine =
SalesLine::findInventTransId(
purchLine.InventRefTransId);
// Production company SalesLine
print icSalesLine.SalesId;
print icSalesLine.ItemId;
print icSalesLine.dataAreaId;
print "------------------";
purchLine =
icSalesLine.interCompanyPurchLine();
// Sales Company PurchLine
print purchLine.PurchId;
print purchLine.ItemId;
print purchLine.dataAreaId;
print "------------------";
salesLine =
purchLine.interCompanySalesLineOriginal();
// Sales Company PurchLine
print salesLine.SalesId;
print salesLine.ItemId;
print salesLine.dataAreaId;
print "------------------";
}
pause;
}
How to catch special keystrokes and use them as shortcuts
Rightclick on a form and go down tracking a specific field or other data, is a tedious work if you do it dozens of times per day.
We wanted to catch the key combination ctrl+Z (since it is rarelly used when running axapta), so we could use it to display common data about a form, field or other info. This is a code example we nowdays always install in all new test and development environments (not production, since it would give normal users unwanted access).
The key to this method is adding code in the Task method of the SysSetupFormRun class. Open your AOT, go to the class SysSetupFormRun, expand the Task method and add the code below between the start/end comments. Save the changes. Start up for example SalesTable form, position on a field and press Ctrl+Z, voila - a complete list of that field is listed in the infolog. Maybe you need to restart your client, to get the changes active.
There is a very similar example on kashperuk.blogspot.com but that example seems to be dependt on a external DLL file, this version is not. Originally this code comes from AxaptaPedia but I can not find it now. We do not claim to be the first with this idea, just showing something very useful. This code goes long back. Our changes is minor.
public int task(int _p1)
{
#task
FormDataSource formDataSource;
int ret;
// START 070921 FourOne/JoJ (FO_EnvironmentAddOns4)
// -- Description: quick-command for checking
// field and/or form data.
SysDictField df;
FormControl fc;
formStringControl fsc;
DictEnum dictEnum = new DictEnum(enumnum(Types));
DictEnum dictEnums;
;
if (_p1 == 769) //Ctrl + Z
{
fc = this.selectedControl();
formDataSource = this.objectSet();
if(fc && formDataSource)
{
fsc = fc;
if(fsc.dataField() && formDataSource.table())
{
info(strfmt('Tbl. Fld -> %2. %1',
fieldId2Name(formDataSource.table(),
fsc.dataField() - 65536),
tableId2Name(formDataSource.table())));
df=new SysDictField(formDataSource.table(),
fsc.dataField() - 65536);
if(df)
{
info(strfmt('Type -> %1',
dictEnum.index2Symbol(
df.baseType())));
if(df.baseType() == typeOf(Types::Enum))
{
dictEnums = new dictEnum(
df.enumId());
info(strfmt('Enum -> %1',
dictEnums.name()));
}
info(strfmt('Ext type -> %1',
extendedTypeId2name(df.typeId())));
info(strfmt('Size -> %1',
int2str(df.stringLen())));
info(strfmt('max.rght -> %1',
(df.rights())));
info(strfmt('Label -> %1: %2',
(df.labelLabel()),(df.label()) ));
info(strfmt('Help -> %1: %2',
(df.helpLabelId()),(df.help()) ));
}
}
if(fsc.dataMethod())
{
info(strfmt('METHOD %1.%2',
tableId2Name(formDataSource.table()),
fsc.dataMethod()));
}
}
}
// END 070921 FourOne/JoJ (FO_EnvironmentAddOns4)
if (_p1 == #taskFilter)
{
formDataSource = this.objectSet();
if (formDataSource &&
formDataSource.queryRun() &&
formDataSource.queryRun().args() &&
!formDataSource.queryRun().args().caller())
{
formDataSource.queryRun().args().caller(this);
}
}
ret = super(_p1);
return ret;
}
We wanted to catch the key combination ctrl+Z (since it is rarelly used when running axapta), so we could use it to display common data about a form, field or other info. This is a code example we nowdays always install in all new test and development environments (not production, since it would give normal users unwanted access).
The key to this method is adding code in the Task method of the SysSetupFormRun class. Open your AOT, go to the class SysSetupFormRun, expand the Task method and add the code below between the start/end comments. Save the changes. Start up for example SalesTable form, position on a field and press Ctrl+Z, voila - a complete list of that field is listed in the infolog. Maybe you need to restart your client, to get the changes active.
There is a very similar example on kashperuk.blogspot.com but that example seems to be dependt on a external DLL file, this version is not. Originally this code comes from AxaptaPedia but I can not find it now. We do not claim to be the first with this idea, just showing something very useful. This code goes long back. Our changes is minor.
public int task(int _p1)
{
#task
FormDataSource formDataSource;
int ret;
// START 070921 FourOne/JoJ (FO_EnvironmentAddOns4)
// -- Description: quick-command for checking
// field and/or form data.
SysDictField df;
FormControl fc;
formStringControl fsc;
DictEnum dictEnum = new DictEnum(enumnum(Types));
DictEnum dictEnums;
;
if (_p1 == 769) //Ctrl + Z
{
fc = this.selectedControl();
formDataSource = this.objectSet();
if(fc && formDataSource)
{
fsc = fc;
if(fsc.dataField() && formDataSource.table())
{
info(strfmt('Tbl. Fld -> %2. %1',
fieldId2Name(formDataSource.table(),
fsc.dataField() - 65536),
tableId2Name(formDataSource.table())));
df=new SysDictField(formDataSource.table(),
fsc.dataField() - 65536);
if(df)
{
info(strfmt('Type -> %1',
dictEnum.index2Symbol(
df.baseType())));
if(df.baseType() == typeOf(Types::Enum))
{
dictEnums = new dictEnum(
df.enumId());
info(strfmt('Enum -> %1',
dictEnums.name()));
}
info(strfmt('Ext type -> %1',
extendedTypeId2name(df.typeId())));
info(strfmt('Size -> %1',
int2str(df.stringLen())));
info(strfmt('max.rght -> %1',
(df.rights())));
info(strfmt('Label -> %1: %2',
(df.labelLabel()),(df.label()) ));
info(strfmt('Help -> %1: %2',
(df.helpLabelId()),(df.help()) ));
}
}
if(fsc.dataMethod())
{
info(strfmt('METHOD %1.%2',
tableId2Name(formDataSource.table()),
fsc.dataMethod()));
}
}
}
// END 070921 FourOne/JoJ (FO_EnvironmentAddOns4)
if (_p1 == #taskFilter)
{
formDataSource = this.objectSet();
if (formDataSource &&
formDataSource.queryRun() &&
formDataSource.queryRun().args() &&
!formDataSource.queryRun().args().caller())
{
formDataSource.queryRun().args().caller(this);
}
}
ret = super(_p1);
return ret;
}
How to add current profile name to the window title
If you use a descriptive text on your profiles you use to startup axapta with, you have here another way of a very clear presentation of which installation, db, etc settings you are running under.
Open your AOT and locate the Info class. Expand the method workspaceWindowCreated and add the following code. Next time you start axapta, your profile name will be part of the axapta window title.
void workspaceWindowCreated(int _hWnd)
{
// Put workspace window specific initialization here.
// -- START 070307 FourOne/HL (EnvironmentAddOns4)
// -- Description: Show profile-name in the title bar
session s=new Session();
;
WinAPI::setWindowText(_hWnd, strFmt("%1 - %2 - %3",
xInfo::configuration(),
s.userId(),
WinAPI::getWindowText(_hWnd) ));
// -- END 070307 FourOne/HL (EnvironmentAddOns4)
}
Open your AOT and locate the Info class. Expand the method workspaceWindowCreated and add the following code. Next time you start axapta, your profile name will be part of the axapta window title.
void workspaceWindowCreated(int _hWnd)
{
// Put workspace window specific initialization here.
// -- START 070307 FourOne/HL (EnvironmentAddOns4)
// -- Description: Show profile-name in the title bar
session s=new Session();
;
WinAPI::setWindowText(_hWnd, strFmt("%1 - %2 - %3",
xInfo::configuration(),
s.userId(),
WinAPI::getWindowText(_hWnd) ));
// -- END 070307 FourOne/HL (EnvironmentAddOns4)
}
How to colour code different companies inside axapta
During development and test we often switch between different companies in our installation. To not mistaken us, so we always make changes in the correct one, we made this small change in the code. With different background-colours for each company, you never delete something importent by mistake. This example shows how it could be done.
Again we use the SysSetupFormRun class, but this time we look into the Run method. Add below code between the start/end comments and restart your client. Next time you start, all forms will have the background colours you set for each specific company.
// --- START 071001 Fourone/JOJ (EnvironmentAddOns4)
// --- Description: Display company 'xxx' with different
// background color
public void run()
{
FormDesign formDesign = this.design();
super();
if (companyinfo::find().dataAreaId=="dmo")
{
if (formdesign)
{
formDesign.colorScheme(2);
formDesign.backgroundColor(0x00ff);
formdesign.caption("-- dmo -- ");
}
}
// --- END 071001 Fourone/JOJ (EnvironmentAddOns4)
}
Again we use the SysSetupFormRun class, but this time we look into the Run method. Add below code between the start/end comments and restart your client. Next time you start, all forms will have the background colours you set for each specific company.
// --- START 071001 Fourone/JOJ (EnvironmentAddOns4)
// --- Description: Display company 'xxx' with different
// background color
public void run()
{
FormDesign formDesign = this.design();
super();
if (companyinfo::find().dataAreaId=="dmo")
{
if (formdesign)
{
formDesign.colorScheme(2);
formDesign.backgroundColor(0x00ff);
formdesign.caption("-- dmo -- ");
}
}
// --- END 071001 Fourone/JOJ (EnvironmentAddOns4)
}
Open filtered forms with X++
When using forms in Dynamics AX we usually get access to them by clicking a button that uses a menu item, this along with the args that is sent we get a form that displays the requested information. But if you want to do this using code, how is this done?
You usually see this used in classes such as SalesFormLetter or PurchFormLetter that uses an existing form instead of a creating a temporary one. The user enters the information and the class uses the new information to perform the tasks at hand.
This is a pretty simple job that first displays a filtered CustTable form for the customer “4004”, when this form is closed the CustTrans form will be opened and display the relevant data of the customer we are using. As this is done you will also see that it’s possible to either halt the code while a form is open or simply detach it and let the code continue.
static void FO_OpenFilteredForms(Args _args)
{
Args argsCust, argsTrans;
FormRun formRun, formRun2;
CustTable custTable = CustTable::find("4004");
;
argsCust = new Args(formStr(CustTable));
argsCust.record(custTable);
formRun = classFactory.formRunClass(argsCust);
formRun.init();
formRun.run();
formRun.wait();
print "This should be printed when " +
"the CustTable form is closed.";
pause;
argsTrans = new Args(formStr(CustTrans));
argsTrans.record(custTable);
formRun2 = classFactory.formRunClass(argsTrans);
formRun2.init();
formRun2.run();
formRun2.detach();
print "This should be printed as " +
"the CustTrans form opens.";
pause;
}
You usually see this used in classes such as SalesFormLetter or PurchFormLetter that uses an existing form instead of a creating a temporary one. The user enters the information and the class uses the new information to perform the tasks at hand.
This is a pretty simple job that first displays a filtered CustTable form for the customer “4004”, when this form is closed the CustTrans form will be opened and display the relevant data of the customer we are using. As this is done you will also see that it’s possible to either halt the code while a form is open or simply detach it and let the code continue.
static void FO_OpenFilteredForms(Args _args)
{
Args argsCust, argsTrans;
FormRun formRun, formRun2;
CustTable custTable = CustTable::find("4004");
;
argsCust = new Args(formStr(CustTable));
argsCust.record(custTable);
formRun = classFactory.formRunClass(argsCust);
formRun.init();
formRun.run();
formRun.wait();
print "This should be printed when " +
"the CustTable form is closed.";
pause;
argsTrans = new Args(formStr(CustTrans));
argsTrans.record(custTable);
formRun2 = classFactory.formRunClass(argsTrans);
formRun2.init();
formRun2.run();
formRun2.detach();
print "This should be printed as " +
"the CustTrans form opens.";
pause;
}
How to Copy Args Object Data
server static void CopyingArgs(Args _args)
{
FormRun _fr;
SysArgs sysArgs;
;
_args = new Args("CustTable");
sysArgs = SysArgs::createFromArgs(_args);
_fr = classFactory.formRunClass(sysArgs);
_fr.init();
_fr.run();
_fr.wait();
}
{
FormRun _fr;
SysArgs sysArgs;
;
_args = new Args("CustTable");
sysArgs = SysArgs::createFromArgs(_args);
_fr = classFactory.formRunClass(sysArgs);
_fr.init();
_fr.run();
_fr.wait();
}
Microsoft Dynamics AX 2009 EP Development Cookbook
Microsoft Dynamics AX 2009 EP Development Cookbook
Click here
Click here
System Classes in Dynamics AX
RandomGenerate Class:
This class generates random numbers.
static void RandomGenerateEg(Args _args)
{
RandomGenerate objRG = new RandomGenerate();
Random objRandom = new Random();
;
//This generates random numbers specified within the given range
info(int2Str(objRG.randomInt(10,55)));
//This generates random numbers
info(int2Str(objRandom.nextInt()));
}
Executing this job generates random numbers. But it doesn’t guarantee that the numbers will not be repeated. So if the user needs unique number, he has to provide explicit check for that
Sequence Class:
Contrary to above class is Sequence class which generates the numbers in order.
static void SequenceEg(Args _args)
{
Sequence objSeq = new Sequence("Test Sequence",8,10,250,1);
print objSeq.currval(); // Displays the current value of the object
while(1)
{
print objSeq.nextval(10);
pause;
}
}
Sequence class takes the following parameters: SequenceName which can be a string of your choice, Identification No for the sequence, Initial Value, Maximum value
and a flag which indicates whether the cycle has to be repeated if maximum value is reached.
The method “nextVal” takes the value to be incremented for next number as parameter.
LastAOTSelection Class:
This class prints the last accessed AOT object by the user.
static void LastAOTSelectionEg(Args _args)
{
LastAOTSelection LS = new LastAOTSelection();
;
print LS.first().toString();
pause;
}
Keywords Class:
Class to list the available functions and keywords in Axapta.
static void KeywordsFunction(Args _args)
{
Keywords objKG = new Keywords();
str strOutput;
;
print Keywords::isValidIdentifier('dddd34'); // This method checks if the identifier is valid or nor
print Keywords::isValidIdentifier('*4532');
pause;
strOutput = objKG.firstFunction();
while(objKG.nextFunction()!= '')
{
strOutput = objKG.nextFunction();
info(stroutput);
}
}
static void KeywordsSymbol(Args _args)
{
Keywords objKG = new Keywords();
str strOutput;
;
strOutput = objKG.firstSymbol();
while (objKG.nextSymbol ()!='')
{
strOutput = objKG.nextSymbol();
info(stroutput);
}
}
This class generates random numbers.
static void RandomGenerateEg(Args _args)
{
RandomGenerate objRG = new RandomGenerate();
Random objRandom = new Random();
;
//This generates random numbers specified within the given range
info(int2Str(objRG.randomInt(10,55)));
//This generates random numbers
info(int2Str(objRandom.nextInt()));
}
Executing this job generates random numbers. But it doesn’t guarantee that the numbers will not be repeated. So if the user needs unique number, he has to provide explicit check for that
Sequence Class:
Contrary to above class is Sequence class which generates the numbers in order.
static void SequenceEg(Args _args)
{
Sequence objSeq = new Sequence("Test Sequence",8,10,250,1);
print objSeq.currval(); // Displays the current value of the object
while(1)
{
print objSeq.nextval(10);
pause;
}
}
Sequence class takes the following parameters: SequenceName which can be a string of your choice, Identification No for the sequence, Initial Value, Maximum value
and a flag which indicates whether the cycle has to be repeated if maximum value is reached.
The method “nextVal” takes the value to be incremented for next number as parameter.
LastAOTSelection Class:
This class prints the last accessed AOT object by the user.
static void LastAOTSelectionEg(Args _args)
{
LastAOTSelection LS = new LastAOTSelection();
;
print LS.first().toString();
pause;
}
Keywords Class:
Class to list the available functions and keywords in Axapta.
static void KeywordsFunction(Args _args)
{
Keywords objKG = new Keywords();
str strOutput;
;
print Keywords::isValidIdentifier('dddd34'); // This method checks if the identifier is valid or nor
print Keywords::isValidIdentifier('*4532');
pause;
strOutput = objKG.firstFunction();
while(objKG.nextFunction()!= '')
{
strOutput = objKG.nextFunction();
info(stroutput);
}
}
static void KeywordsSymbol(Args _args)
{
Keywords objKG = new Keywords();
str strOutput;
;
strOutput = objKG.firstSymbol();
while (objKG.nextSymbol ()!='')
{
strOutput = objKG.nextSymbol();
info(stroutput);
}
}
Number sequence implementation in Dynamics ax
You can download the document for implementing the number sequence form here
Using while select firstonly to avoid validations in Dynamics Ax
static void WhileSelectInsteadoFSelect(Args _args)
{
InventTable inventTable;
;
-----General way---------
//fetch the record first
select firstonly forupdate inventtable;
//add an additional validation
if (inventTable.recid)
{
inventTable.itemName = 'newname';
inventTable.update();
}
------Alternate--------------
//prevents the extra 'if' chek
while select firstonly forupdate inventTable
{
inventTable.itemName = 'newname';
inventTable.update();
}
//can also be used for simple readonly
while select firstonly inventTable
{
Info(inventTable.ItemId);
}
}
{
InventTable inventTable;
;
-----General way---------
//fetch the record first
select firstonly forupdate inventtable;
//add an additional validation
if (inventTable.recid)
{
inventTable.itemName = 'newname';
inventTable.update();
}
------Alternate--------------
//prevents the extra 'if' chek
while select firstonly forupdate inventTable
{
inventTable.itemName = 'newname';
inventTable.update();
}
//can also be used for simple readonly
while select firstonly inventTable
{
Info(inventTable.ItemId);
}
}
Finding if a node is existing in lower layers Dynamics Ax
UtilEntryLevel getHighestBelowCurLayer(TreeNode _treeNode)
{
UtilEntryLevel layer, highestLayer;
;
for (layer=UtilEntryLevel::sys; layer < UtilEntryLevel::bus; layer++)
{
if (SysTreeNode::isNodeInLayer(_treeNode, layer))
{
highestLayer = layer;
break;
}
}
return highestLayer;
}
{
UtilEntryLevel layer, highestLayer;
;
for (layer=UtilEntryLevel::sys; layer < UtilEntryLevel::bus; layer++)
{
if (SysTreeNode::isNodeInLayer(_treeNode, layer))
{
highestLayer = layer;
break;
}
}
return highestLayer;
}
Opening the Project node automatically in Dynamics Ax
static void JobOpeningProjectNodeInAoT(Args _args)
{
ProjectNode sharedProject = Infolog.projectRootNode().AOTfindChild('Shared');
ProjectNode projectNode = sharedProject.AOTfindChild('Docu');
;
if (projectNode)
{
projectNode.getRunNode();
}
}
{
ProjectNode sharedProject = Infolog.projectRootNode().AOTfindChild('Shared');
ProjectNode projectNode = sharedProject.AOTfindChild('Docu');
;
if (projectNode)
{
projectNode.getRunNode();
}
}
Exists methods don’t need table declaration in Dynamics Ax
static boolean SelectStatementInBooleanConditions()
{
//no declaration for table object has been made.
boolean test;
;
//testing a variable
test = (select firstonly salesTable).salesId ? true : false;
//if condition
if ((select firstonly salesTable).recid)
{
return true;
}
//switch statement
switch ((select firstonly salesTable).recid)
{
case 0:
return true;
case 1:
return false;
default:
return false;
}
//return statement
return ((select firstonly salesTable).recid);
}
{
//no declaration for table object has been made.
boolean test;
;
//testing a variable
test = (select firstonly salesTable).salesId ? true : false;
//if condition
if ((select firstonly salesTable).recid)
{
return true;
}
//switch statement
switch ((select firstonly salesTable).recid)
{
case 0:
return true;
case 1:
return false;
default:
return false;
}
//return statement
return ((select firstonly salesTable).recid);
}
Design Pattern used in Dynamics Ax Click here
Design Pattern used in Dynamics Ax Click here
Click here for Image
Click here for Image
Executing SQL directly from X++
The X++ language supports a number of ways to execute native SQL against any SQL data source. Below are two samples for retrieving data as well as manipulating data. Please be aware, that SQL can be really powerful, and it should be used as such.
Example #1: Retrieve data:
Since this example uses a Connecion class, data is retrieved from the database where Axapta is currently connected.
void Sample_1(void)
{
Connection Con = new Connection();
Statement Stmt = Con.createStatement();
ResultSet R =Stmt.executeQuery(‘SELECT VALUE FROM SQLSYSTEMVARIABLES’);
while ( R.next() )
{
print R.getString(1);
}
}
Example #2: Manipulating data (deletion):
void Sample_2(void)
{
str sql;
Connection conn;
SqlStatementExecutePermission permission;
;
sql = ‘delete from custTable’;
permission = new SqlStatementExecutePermission(sql);
conn = new Connection();
permission = new SqlStatementExecutePermission(sql);
permission.assert();
conn.createStatement().executeUpdate(sql);
// the permissions needs to be reverted back to original condition.
CodeAccessPermission::revertAssert();
}
Example #1: Retrieve data:
Since this example uses a Connecion class, data is retrieved from the database where Axapta is currently connected.
void Sample_1(void)
{
Connection Con = new Connection();
Statement Stmt = Con.createStatement();
ResultSet R =Stmt.executeQuery(‘SELECT VALUE FROM SQLSYSTEMVARIABLES’);
while ( R.next() )
{
print R.getString(1);
}
}
Example #2: Manipulating data (deletion):
void Sample_2(void)
{
str sql;
Connection conn;
SqlStatementExecutePermission permission;
;
sql = ‘delete from custTable’;
permission = new SqlStatementExecutePermission(sql);
conn = new Connection();
permission = new SqlStatementExecutePermission(sql);
permission.assert();
conn.createStatement().executeUpdate(sql);
// the permissions needs to be reverted back to original condition.
CodeAccessPermission::revertAssert();
}
how to capitalize all letters
tsBegin;
while
select forUpdate myTable
{
myTable.Description = strUpr(myTable.Description);
myTable.update();
}
ttsCommit
while
select forUpdate myTable
{
myTable.Description = strUpr(myTable.Description);
myTable.update();
}
ttsCommit
Multidimensional Expressions (MDX) click here
Introduction to Multidimensional Expressions (MDX) Click Here for PDF
This tutorial introduces multidimensional expressions (MDX), a highly
functional expression syntax for querying multidimensional data in Microsoft SQL
Server OLAP Services. It also discusses the structure of OLAP Services cubes and
explores the features of MDX.
See the attached file for more details
This tutorial introduces multidimensional expressions (MDX), a highly
functional expression syntax for querying multidimensional data in Microsoft SQL
Server OLAP Services. It also discusses the structure of OLAP Services cubes and
explores the features of MDX.
See the attached file for more details
Advance Data Types || Collection classes in AX 2012
Advance Data Types
1.List Class
2.Map Class
3.Set Class
4.Container
5.RecordSortedList
6.RecordInsertList
7.Temp table.
1.List Class
2.Map Class
3.Set Class
4.Container
5.RecordSortedList
6.RecordInsertList
7.Temp table.
Add AOT query to SysQueryForm
Below code can be used to add any AOT query to SysQueryForm.
SysQueryRun queryRun = new SysQueryRun(queryStr(TestQuery));
queryRun.form(formstr(SysQueryForm));
queryRun.title(‘Select a record’);
queryRun.prompt();
SysQueryRun queryRun = new SysQueryRun(queryStr(TestQuery));
queryRun.form(formstr(SysQueryForm));
queryRun.title(‘Select a record’);
queryRun.prompt();
Restoring the Database with the SQL command
RESTORE DATABASE AXDB
FROM DISK = ‘d:\test.bak’
WITH REPLACE
FROM DISK = ‘d:\test.bak’
WITH REPLACE
List class
List Class
Contains any number of elements that are accessed sequentially.
Lists are structures that can contain values of any X++ type.
All the values in the list must be of the same type. Type is defined when the list is created and cannot be changed.
All X++ types can be accessable using enum Types::
Lists can be traversed by using the Enumerator , ListEnumerator class. To create a ListEnumerator object, use List.getEnumerator.
First Example
List list = new List(Types::Integer);
Enumerator en ;
list.addEnd(333333); // add the value at last
list.addEnd(111111);
list.addEnd(222222);
en = list.getEnumerator();
print list.elements(); //"print number of element"
while (en.moveNext())
{
print en.current();
}
pause;
Second Example
List list1 = new List(Types::Integer);
List list2 = new List(Types::Integer);
List combinedList = new List(Types::Integer);
int i;
;
for(i=1; i<6; i++)
{
List1.addEnd(i);
}
for(i=6; i<11; i++)
{
List2.addEnd(i);
}
combinedList = List::merge(list1, list2);
print combinedList.toString();
pause;
Contains any number of elements that are accessed sequentially.
Lists are structures that can contain values of any X++ type.
All the values in the list must be of the same type. Type is defined when the list is created and cannot be changed.
All X++ types can be accessable using enum Types::
Lists can be traversed by using the Enumerator , ListEnumerator class. To create a ListEnumerator object, use List.getEnumerator.
First Example
List list = new List(Types::Integer);
Enumerator en ;
list.addEnd(333333); // add the value at last
list.addEnd(111111);
list.addEnd(222222);
en = list.getEnumerator();
print list.elements(); //"print number of element"
while (en.moveNext())
{
print en.current();
}
pause;
Second Example
List list1 = new List(Types::Integer);
List list2 = new List(Types::Integer);
List combinedList = new List(Types::Integer);
int i;
;
for(i=1; i<6; i++)
{
List1.addEnd(i);
}
for(i=6; i<11; i++)
{
List2.addEnd(i);
}
combinedList = List::merge(list1, list2);
print combinedList.toString();
pause;
Query “join table A with table B and table A with table C”
//
Query query = new Query();
QueryBuildDataSource qbds,qbds1,qbds2;
qbds = query.addDataSource(tableNum(CustTable));
qbds1 = qbds.addDataSource(tableNum(CustTrans));
qbds2 = qbds1.addDataSource(tableNum(CustLedgerTransTypeMapping));
qbds1.addLink(fieldNum(CustTrans,AccountNum),fieldNum(CustTable,AccountNum));
qbds2.addLink(fieldNum(CustTrans,TransType),fieldNum(CustLedgerTransTypeMapping,CustSettleTransType));
info(query.toString());
------------------
static void Job20(Args _args)
{
Query q;
QueryRun qr;
QueryBuildDatasource qbds1, qbds2;
QueryBuildRange qbr;
LedgerTable _LedgerTable;
;
q = new Query();
qbds1 = q.addDataSource(tablenum(LedgerTable));
qbds2 = qbds1.addDataSource(tablenum(LedgerTrans));
qbds2.relations(TRUE); //this enforces a relationship between this datasource and its parent. Relationships defined in the Data Dictionary are used by default.
qbr = qbds1.addRange(fieldnum(LedgerTable,
AccountNum));
//qbr.value(SysQuery::value("10000")); //SysQuery object provides various static methods to assist in defining Query criteria. The SysQuery::value() method should always be used when defining a singular value for a range.
qr = new QueryRun(q);
while(qr.next())
{
//do something
info(_LedgerTable.AccountNum);
}
}
Query query = new Query();
QueryBuildDataSource qbds,qbds1,qbds2;
qbds = query.addDataSource(tableNum(CustTable));
qbds1 = qbds.addDataSource(tableNum(CustTrans));
qbds2 = qbds1.addDataSource(tableNum(CustLedgerTransTypeMapping));
qbds1.addLink(fieldNum(CustTrans,AccountNum),fieldNum(CustTable,AccountNum));
qbds2.addLink(fieldNum(CustTrans,TransType),fieldNum(CustLedgerTransTypeMapping,CustSettleTransType));
info(query.toString());
------------------
static void Job20(Args _args)
{
Query q;
QueryRun qr;
QueryBuildDatasource qbds1, qbds2;
QueryBuildRange qbr;
LedgerTable _LedgerTable;
;
q = new Query();
qbds1 = q.addDataSource(tablenum(LedgerTable));
qbds2 = qbds1.addDataSource(tablenum(LedgerTrans));
qbds2.relations(TRUE); //this enforces a relationship between this datasource and its parent. Relationships defined in the Data Dictionary are used by default.
qbr = qbds1.addRange(fieldnum(LedgerTable,
AccountNum));
//qbr.value(SysQuery::value("10000")); //SysQuery object provides various static methods to assist in defining Query criteria. The SysQuery::value() method should always be used when defining a singular value for a range.
qr = new QueryRun(q);
while(qr.next())
{
//do something
info(_LedgerTable.AccountNum);
}
}
An eaxmple of List data structure in AX
static void ListSample(Args _args)
{
List list = new List(Types::Record);
Enumerator en ;
list.addEnd(333333);
list.addEnd(111111);
list.addEnd(222222);
en = list.getEnumerator();
while (en.moveNext())
{
print en.current();
}
pause;
}
{
List list = new List(Types::Record);
Enumerator en ;
list.addEnd(333333);
list.addEnd(111111);
list.addEnd(222222);
en = list.getEnumerator();
while (en.moveNext())
{
print en.current();
}
pause;
}
How to delete the Enum value at runtime
//if i need to delete the enum value at run time then what i need to do?
//Example has 3 values
//Enum::value1
//Enum::value2
//Enum::value3
//Answer: you need to overview the enter event of control from design and write the following //line.
combobox:enter()
{
super();
this.delete(enum2str(Enum::value2));
}
//Example has 3 values
//Enum::value1
//Enum::value2
//Enum::value3
//Answer: you need to overview the enter event of control from design and write the following //line.
combobox:enter()
{
super();
this.delete(enum2str(Enum::value2));
}
05 October 2010
04 October 2010
Creating Table with X++ Code
static void Create_Table_with_Code(Args _args)
{
SysDictTable sysdictTable;
treenode trv;// its a class
AOTTableFieldList fieldnode;
str prop;
int pos;
#AOT
#Properties
;
//#Table path refer the \\Data Dictionary\\Tables and finding the path
trv = treenode::findNode(#TablesPath);
//AOTadd method is to add table in tables//AAA is table name
trv.AOTadd('AAA');
trv = trv.AOTfindChild('AAA');
trv.AOTcompile(1);
trv.AOTsave();
trv.AOTfindChild('AAA');
fieldnode = trv.AOTfirstChild();
fieldnode.addString('AccountNum');
fieldnode = fieldnode.AOTfindChild('AccountNum');
prop = fieldnode.AOTgetProperties();
pos = findPropertyPos(prop,#PropertyExtendeddatatype); //find right place to put extended data type
pos = strFind(prop,'ARRAY',pos,strLen(prop));
pos = strFind(prop,'#',pos,strLen(prop));
prop = strins(prop,extendedTypeId2name(ExtendedtypeNum(CustAccount)),pos + 1);
// insert field of extended data type 'CustAccount'
fieldnode.AOTsetProperties(prop);
trv.AOTcompile(1);
trv.AOTsave();
trv.AOTRestore(); //to load assigned extended data type properties
sysdictTable = sysdictTable::newTreeNode(trv);
appl.dbSynchronize(sysdictTable.id());
}
{
SysDictTable sysdictTable;
treenode trv;// its a class
AOTTableFieldList fieldnode;
str prop;
int pos;
#AOT
#Properties
;
//#Table path refer the \\Data Dictionary\\Tables and finding the path
trv = treenode::findNode(#TablesPath);
//AOTadd method is to add table in tables//AAA is table name
trv.AOTadd('AAA');
trv = trv.AOTfindChild('AAA');
trv.AOTcompile(1);
trv.AOTsave();
trv.AOTfindChild('AAA');
fieldnode = trv.AOTfirstChild();
fieldnode.addString('AccountNum');
fieldnode = fieldnode.AOTfindChild('AccountNum');
prop = fieldnode.AOTgetProperties();
pos = findPropertyPos(prop,#PropertyExtendeddatatype); //find right place to put extended data type
pos = strFind(prop,'ARRAY',pos,strLen(prop));
pos = strFind(prop,'#',pos,strLen(prop));
prop = strins(prop,extendedTypeId2name(ExtendedtypeNum(CustAccount)),pos + 1);
// insert field of extended data type 'CustAccount'
fieldnode.AOTsetProperties(prop);
trv.AOTcompile(1);
trv.AOTsave();
trv.AOTRestore(); //to load assigned extended data type properties
sysdictTable = sysdictTable::newTreeNode(trv);
appl.dbSynchronize(sysdictTable.id());
}
Add Fields to a table, using X++ code_not the AOT In Dynamics Ax
// Create a New table in AOT with the name of moDocuref
static void createFieldFromCode(Args _args)
{
#AOT
TreeNode tableNode;
AotTableFieldList myAOTTablefieldList;
SysDictTable sysDictTable = new SysDictTable(tablenum(moDocuref));
;
if (! hasSecuritykeyAccess(securitykeynum(SysDevelopment),AccessType::View))
{
return;
}
myAOTTablefieldList = new AotTableFieldList();
tableNode = TreeNode::findNode(#TablesPath+'\\'+sysDictTable.name());
myAOTTablefieldList = TreeNode::findNode(#TablesPath+'\\'+sysDictTable.name() + "\\Fields");
if(!myAOTTablefieldList.AOTfindChild("newField")) // check if the field alredy exists
{
myAOTTablefieldList.addString("newField");
}
tableNode.AOTsave();
}
static void createFieldFromCode(Args _args)
{
#AOT
TreeNode tableNode;
AotTableFieldList myAOTTablefieldList;
SysDictTable sysDictTable = new SysDictTable(tablenum(moDocuref));
;
if (! hasSecuritykeyAccess(securitykeynum(SysDevelopment),AccessType::View))
{
return;
}
myAOTTablefieldList = new AotTableFieldList();
tableNode = TreeNode::findNode(#TablesPath+'\\'+sysDictTable.name());
myAOTTablefieldList = TreeNode::findNode(#TablesPath+'\\'+sysDictTable.name() + "\\Fields");
if(!myAOTTablefieldList.AOTfindChild("newField")) // check if the field alredy exists
{
myAOTTablefieldList.addString("newField");
}
tableNode.AOTsave();
}
Subscribe to:
Posts (Atom)
Ledger Voucher creation Framework and x++ code to create ledger voucher
Please click her for MS reference file Below is the out of the box example reference and code. SalesInvoiceJournalPostSubBill_Extension-...
-
{ "Message" : "Please verify that the user is valid and set up correctly." } Sol: System Administration > Se...
-
Please click here to access Custom Workflow step by step process:
-
FormRun formRun = sender.formRun(); Object inventTrans_ds = formRun.dataSource(formDataSourceStr(InventMarking,InventTransO...