Sunday, December 8, 2013
Microsoft Dynamics Ax Roadmap
Hi guys,
We learn many small things in our daily Ax work. I thought
it would be beneficial for all of us if we share them. I am going to start a
daily mail on Ax which may contain
Ø
Did you know – News on Ax
Ø
Code snippets
Ø
Trouble shooting
Ø
Other technical stuff
Please spend couple of minutes per day to read the mail and
add a point to your Ax learning.
Did you know?
Microsoft Dynamics Ax
Roadmap
How to call events on a Dialog in Ax2012
I found a way in which we can
override the form events like modified, lookup, clicked etc. on a Dialog.
We used to create event method on a dialog by using “FieldNumber_1_event”
format. I got a requirement in which I have to show the lookup for
service orders on the basis of project id on a dialog. I did it in a following
way instead of we used to do in Ax2009.
·
Overwrite
dialogPostRun method and wrote the following code
public void dialogPostRun(DialogRunbase _dialog)
{
FormRun formRun;
super(_dialog);
formRun =
_dialog.dialogForm().formRun();
formRun.controlMethodOverload(true);
formRun.controlMethodOverloadObject(this);
fsCtrlSmmActivityNumber =
formRun.design().control(fbsCtrlSmmActivityNumber.id());
fsCtrlProjCategoryId =
formRun.design().control(fbsCtrlProjCategoryId.id());
_dialog.dialogForm().formRun().controlMethodOverload(false);
_dialog.dialogForm().formRun().controlMethodOverloadObject(this);
//
2012-10-02 #18679 pgad: Project adjustments -->
dialogServiceOrderId.registerOverrideMethod(methodStr(FormStringControl,
lookup), methodStr(ProjAdjustmentSplit, serviceOrderLookup), this);
// 2012-10-02 #18679 pgad: Project
adjustments <-- o:p="">-->
}
·
Here I have
registered event lookup.
·
Created one
static method serviceOrderLookup.
public
void serviceOrderLookup(FormStringControl _formStringControl)
{
boolean ret;
;
ret = _formStringControl.modified();
if (ret)
{
this.lookup(); ( this will call the lookup method on a ProjAdjustmentSplit)
}
}
·
Now it will
call lookup event automatically. We need not to handle this
AX 2012 Buffer size exceeded
Issue encountered where a query exceeded the Buffer Size. Error reported as
Statement too long and AX suggests increasing the size of the buffer in the AOS
database configuration tab.
The default for this buffer is 24K and most documentation suggests if there is a need to increase the size of this buffer as a result of either a query or select statement that is should only be increased by small increments.
However, there is an alternative method of resolving this and that is to use the forceLiterals attribute/property. To do this on a AX query, set the Literal property of the query from Default to forceLiteral. If the issue arises on a AX X++ select statement then use the keyword forceliterals eg
You are advised not to use the forceLiterals keyword in X++ select statements, because it could expose code to an SQL injection security threat.
The default for this buffer is 24K and most documentation suggests if there is a need to increase the size of this buffer as a result of either a query or select statement that is should only be increased by small increments.
However, there is an alternative method of resolving this and that is to use the forceLiterals attribute/property. To do this on a AX query, set the Literal property of the query from Default to forceLiteral. If the issue arises on a AX X++ select statement then use the keyword forceliterals eg
select forceliterals custtable;
Note
You are advised not to use the forceLiterals keyword in X++ select statements, because it could expose code to an SQL injection security threat.
AX 2012:- Business Framework
We as AX developers at some point have
developed functionalities wherein we need to take some input from the user and
based on that input some processing needs to be done in batch. When such
requirements come up, the first thing that comes to our mind is RunBase and
RunBaseBatch.
I would like to introduce a framework introduced in AX2012,
the still is derived from RunBaseBatch but it is a lot easier to perform tasks
like building the dialog UI, validate the user entered input and retrieve user
entered input for processing. Well in the introduction (to keep it simple),
we’ll take only these three objectives.
Requirement
Suppose, I have a requirement of displaying to user a dialog
in which he/she can enter following fields through a dialog
i.
Name (String)
ii.
Greeting Count (Any number not greater than 10)
After pressing OK, user sees an info log of a greeting, as
many numbers of times as he had entered in the second field.
Solution
The above solution when build by deriving class from
RunBaseBatch will need a class extended from RunBaseBatch. That single class
will handle building of user interface in the dialog, validate user input in the
dialog fields and perform required processing on the user input. However, when
using Business Operation Framework, we can split this into individual tasks.
Let’s build the above requirements with Business Operation Framework.
Data Contract Class
First we need a data contract class for the operation
framework. The data contract class will contain parm methods to retrieve user
entered values from the dialog. Assuming we have an integer based EDT named
GreetCount.
[DataContractAttribute]
class
GreetOperationDataContract
{
GreetCount
greetCount;
Name
usersName;
}
[DataMemberAttribute]
public GreetCount
parmGreetCount(greetCount _greetCount = greetCount)
{
greetCount =
_greetCount;
return
greetCount;
}
[DataMemberAttribute]
public Name parmUsersName(Name
_usersName = usersName)
{
usersName =
_usersName;
return
usersName;
}
Service Class
Next we a class that performs the required operation of
displaying a greeting infolog the required number of times.
class GreetService
{
}
public void
showGreetingInfolog(GreetOperationDataContract _dataContract)
{
int
i;
for(i =
0; i < _dataContract.parmGreetCount();
i++)
{
info(strFmt("Hello %1. No. %2",
_dataContract.parmUsersName(), i));
}
}
Service Controller Class
class GreetServiceController
extends SysOperationServiceController
{
}
public static
void main(args _args)
{
GreetServiceController
greetController;
greetController =
GreetServiceController::construct();
greetController.parmExecutionMode(SysOperationExecutionMode::Synchronous);
greetController.startOperation();
}
public static
GreetServiceController construct()
{
return
new GreetServiceController();
}
public ClassDescription
caption()
{
return
"Greeting to Operation framework";
}
public void
new()
{
super();
this.parmClassName(classstr(GreetService));
this.parmMethodName(methodStr(GreetService,
showGreetingInfolog));
}
public LabelType
parmDialogCaption(LabelType _dialogCaption = "")
{
LabelType ret;
ret =
this.caption();
return
ret;
}
User Interface Builder Class
The user interface builder class is needed only if you wish
to perform some validations on the user input, or create a custom lookup on some
dialog field.
class GreetUIBuilder
extends SysOperationAutomaticUIBuilder
{
DialogField
dlgGreetCount;
}
public boolean
greetCountValidate(FormIntControl _control)
{
if
(_control.value() > 10)
{
return
checkFailed("Please enter a number less than 10");
}
return
true;
}
public void
postBuild()
{
super();
dlgGreetCount =
this.bindInfo().getDialogField(this.dataContractObject(),
methodStr(GreetOperationDataContract,
parmGreetCount));
}
public void
postRun()
{
super();
dlgGreetCount.registerOverrideMethod(methodStr(FormIntControl,
validate), methodStr(GreetUIBuilder, greetCountValidate),
this);
}
Output
Run the controller class to see the output.
And in the Greet # field try to enter a value greater than 10. If you choose to
run this operation in batch, you can go to System Administration -> Inquiries
-> Batch jobs -> Batch jobs or (Batch jobs history) to view the status of
the batch job. Select the operation "Greeting to operation framework" and click
button Log. Will see the output.
Enhancement in Financial Dimension Lookup functionality
The
below form shows all financial dimensions used in client’s company. I will show
the functionality related to dimension Avdeling,
which is a custom dimension.
After clicking the button Financial dimension values on the above form, the below form gets
open:
On the left side of the above form, all dimension values are
being shown and on the right side all the properties of the selected dimension
value are displayed. There is a field on right side “Select the level of
dimension value to display” which contains 3 values: Shared Values, Chart of
Accounts and Companies.
In std
AX 2012, if the field Suspended is
ticked while Shared Values is
selected in the above mentioned field then this dimension value will not be
displayed in the look up of Avdeling
dimension in segmented control as well as in dimension look up in
customer/vendor master etc. form. When
the Companies option is selected
then we can set properties/values for all companies separately as shown below:
The client requirement
was that if the Companies is
selected in level field and the suspended check box is marked for some
particular company then the selected dimension value should not be displayed in
dimension lookup in that company.
So if the value 01 is suspended in company 001 then it
should not be displayed in the lookup in company 001 and if it is not suspended
in 002 then it should be displayed in 002.
Below form is General Journal lines form which is using
segmented entry control to enter dimension values.
Now I will show you the code which is used to show the
dimensions in look up of segmented controls:
In std AX 2012, there was only below code written in red
area:
LedgerDimensionController::restrictQueryDimensionAttributeValues(_qbds,
_dimensionAttributeId, false, false);
I created one more
method LedgerDimensionController::restrictQueryDimensionAttributeValuesLed which will be called in case
of dimensions (Not in case of Main Account selection).
Both methods have been shown below
I added one more data
source(DimensionAttrValueLedgerOverride) to the main data source and put the
condition of not to show the suspended dimension here. The changes, I made in
std method, have been shown below in red area:
By using the above
method, the dimension lookup in segmented control was showing only dimensions
which were not suspended in that company.
The client wanted the same logic of dimensions in
normal dimension look up also e.g. in Journals/Customer/Vendor etc. forms as
shown below:
I have shown the code below to be used in normal dimension
lookup. The below changes are done in init
method of DimensionDefaultLookup
form. My changes are shown in red area.
Count of number of pages printed on to SSRS report
public void
reportViewerRefreshComplete(SRSReportExecutionInfo _executionInfo)
{
int page;
super(_executionInfo);
page =
this.getReportContract().parmReportExecutionInfo().parmPrintedPhysicalPages();
info("Total number of pages:" + int2str(page));
}
Subscribe to:
Posts (Atom)












