Every once in a while you will get some strange errors in your code - in the pre-2012 R3/R2 releases of AX without the axbuild command, doing a full X++ compile is quite time consuming.
As known, without an error-free X++ compile, the CIL compile will fail, so how can developers easily find any X++ errors if the CIL compile fails? Sure, do the full X++ compile, but wait, there is more.
A quick way to find X++ errors after an unsuccessful fuld CIL generation is to look in the CIL generation log.
The log can be found on the AOS-server in the relevant AOS-instance's program files, e.g.
"C:\Program Files\Microsoft Dynamics AX\60\Server\[Instance name]\bin\XppIL\Dynamics.Ax.Application.dll.log"
You want the log to look like this
Wednesday, 6 May 2015
Friday, 17 April 2015
Assigning enum value to variable from enum name
Working with utilities there are alot of file exchanges - alot.
Today we got a strange case though. In a file we receive a value that represents the name of a enum value, e.g. E17. The label of the enum value is Consumption, so we wanted to assign the value to a field value in a given table, so this is what we came up with
we also came up with this one where we inserted the option of a small if-statement to check if the name of the enum value is found on the enum:
Today we got a strange case though. In a file we receive a value that represents the name of a enum value, e.g. E17. The label of the enum value is Consumption, so we wanted to assign the value to a field value in a given table, so this is what we came up with
// must assign Consupmtion and not E17
JournalConnection
journalConnection;
str typeOfMeteringPoint
= "E17";
SysDictEnum
dictEnum = new
SysDictEnum(enumNum(ConnectionTypes));
;
journalConnection.type =
dictEnum.symbol2Value(typeOfMeteringPoint);
we also came up with this one where we inserted the option of a small if-statement to check if the name of the enum value is found on the enum:
JournalConnection
journalConnection;
ConnectionTypes
connectionTypes;
str
typeOfMeteringPoint = "E17";
SysDictEnum
dictEnum = new
SysDictEnum(enumNum(ConnectionTypes));
Counter
values = dictEnum.values();
int
idx;
;
for(idx
= 0; idx< values ;idx++)
{
if(typeOfMeteringPoint
== dictEnum.index2Symbol(idx))
{
journalConnection.type = str2enum(ConnectionTypes,dictEnum.index2Name(idx));
}
}
Tuesday, 31 March 2015
Primary legal entity primary address and country code specific menu items
Earlier this week a customer experienced that a very important menu item all of a sudden disappeared. It was quite disturbing since it is the call center's main entry point for calls.
I could see the menu item in AOT > Menus but when I opened the element I got this error message:
I knew that the Menu Item in question had a CountryRegionCode property set to Denmark (DK)
and that the License configuration had Denmark set in Country/Regional specific feature:
My immediate thought was that the customer had altered the role for the users, however when I logged on to the clients environment with the System Administrator role, the menu item still was unavailable.
So, what was the problem? I could confirm that it had something to do with the CountryRegionCode by doing some tests.
With AX 2012 the controlling party is defined by the organization model. "If the country context of the controlling party matches the country context of the controlled entity, the functionality or UI elements will be enabled." (MSDN-article "Applying Country Specific Functionality [AX 2012]")
So the country region code of the primary address of the legal entity defines the country/region context for the controlling party - which means that if there is no primary address or the primary address is not in the same country as the menu item, the UI element will not be shown.
The resolution was to check if the Legal entity had Denmark as country code for the primary address:
which it did not - they had altered the country region for the primary address for no reason.
Once the primary address' country region was edited back to Denmark, the menu item appeared again.
I could see the menu item in AOT > Menus but when I opened the element I got this error message:
I knew that the Menu Item in question had a CountryRegionCode property set to Denmark (DK)
and that the License configuration had Denmark set in Country/Regional specific feature:
My immediate thought was that the customer had altered the role for the users, however when I logged on to the clients environment with the System Administrator role, the menu item still was unavailable.
So, what was the problem? I could confirm that it had something to do with the CountryRegionCode by doing some tests.
With AX 2012 the controlling party is defined by the organization model. "If the country context of the controlling party matches the country context of the controlled entity, the functionality or UI elements will be enabled." (MSDN-article "Applying Country Specific Functionality [AX 2012]")
So the country region code of the primary address of the legal entity defines the country/region context for the controlling party - which means that if there is no primary address or the primary address is not in the same country as the menu item, the UI element will not be shown.
The resolution was to check if the Legal entity had Denmark as country code for the primary address:
Open the Legal entities form:
Once the primary address' country region was edited back to Denmark, the menu item appeared again.
Thursday, 5 March 2015
Microsoft Dynamics AX 2012 R3 and Azure
Back in November 2013 Mary Jo Foley reported that Microsoft planned to Dynamics AX to the clould by spring 2014.
With the release of Dynamics AX 2012 R3 Microsoft introduced the ability of deploying AX 2012 R3 to the Cloud, proving once again that Mary Jo Foley's articles are well worth reading when it comes to news on Microsoft and their products. While Microsoft have updated their articles on how to plan a AX deployment to the cloud, the move to a cloud based solution may seem a challenge if you never before have investigated Azure.
In order to get the fundamentals in place, Microsoft have published a free e-book. It is a great read, not only covering many of the topics that are relevant for a Dynamics AX 2012 R3 implementation but will also covering areas for general development.
Download your copy from:
http://blogs.msdn.com/b/microsoft_press/archive/2015/02/03/free-ebook-microsoft-azure-essentials-fundamentals-of-azure.aspx
With the release of Dynamics AX 2012 R3 Microsoft introduced the ability of deploying AX 2012 R3 to the Cloud, proving once again that Mary Jo Foley's articles are well worth reading when it comes to news on Microsoft and their products. While Microsoft have updated their articles on how to plan a AX deployment to the cloud, the move to a cloud based solution may seem a challenge if you never before have investigated Azure.
In order to get the fundamentals in place, Microsoft have published a free e-book. It is a great read, not only covering many of the topics that are relevant for a Dynamics AX 2012 R3 implementation but will also covering areas for general development.
Download your copy from:
http://blogs.msdn.com/b/microsoft_press/archive/2015/02/03/free-ebook-microsoft-azure-essentials-fundamentals-of-azure.aspx
Tuesday, 3 March 2015
Videos from Technical Conference 2015
The annual Microsoft Dynamics Techical Conference took place back in February. As always the conference demonstrated Microsoft's strong commitment to the Dynamics Product portfolio and gave participants the opportunity to hear about practical and technical content, as well as recommended best practices, delivered by Microsoft leaders and technology experts.
The videos from the conference are now available from Customer and Partner Source site:
Saturday, 28 February 2015
2 examples of importing multiple files
In AX, the typical way to import files via the UI is to do it one file at the time. If you have multiple files to import there are several options on how to do this via the AIF.
Every once in a while, it could be useful for the end-user to have the option of importing several files through the UI.
I have found two similar examples on how to achieve this:
Example 1)
static void MultiFileSelectDlgTest_1(Args _args)
{
System.Windows.Forms.OpenFileDialog ofd;
System.String[] s2;
int counters;
str imageValaue;
int i;
;
ofd = new System.Windows.Forms.OpenFileDialog();
ofd.set_Title("Select files");
ofd.set_Multiselect(true);
if (ofd.ShowDialog() == System.Windows.Forms.DialogResult::OK)
{
s2 = ofd.get_FileNames();
counters=System.Convert::ToInt32( s2.get_Length());
for(i = 0 ; i <= counters-1; i++)
{
imageValaue = System.Convert::ToString(s2.GetValue(i));
info(strFmt('%1', imageValaue));
//do whatever you want ;)
}
}
}
The dialog will show this:
Every once in a while, it could be useful for the end-user to have the option of importing several files through the UI.
I have found two similar examples on how to achieve this:
Example 1)
static void MultiFileSelectDlgTest_1(Args _args)
{
System.Windows.Forms.OpenFileDialog ofd;
System.String[] s2;
int counters;
str imageValaue;
int i;
;
ofd = new System.Windows.Forms.OpenFileDialog();
ofd.set_Title("Select files");
ofd.set_Multiselect(true);
if (ofd.ShowDialog() == System.Windows.Forms.DialogResult::OK)
{
s2 = ofd.get_FileNames();
counters=System.Convert::ToInt32( s2.get_Length());
for(i = 0 ; i <= counters-1; i++)
{
imageValaue = System.Convert::ToString(s2.GetValue(i));
info(strFmt('%1', imageValaue));
//do whatever you want ;)
}
}
}
The dialog will show this:
and the output in the infolog shows the individual files processed:
Example 2) The second example is just another flavour of the first, adding a filter option on the input content.
static void MultiFileSelectDlgTest_2(Args _args)
{
int idx;
int cnt;
boolean result;
System.String[] files;
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.set_Multiselect(true);
dlg.set_DefaultExt(".txt");
dlg.set_Filter("Text documents|*.txt|All files|*.*");
result = dlg.ShowDialog();
if (result)
{
files = dlg.get_FileNames();
cnt = files.get_Count();
for (idx = 0; idx <= cnt; idx++)
{
info(files.get_Item(idx));
}
}
}
Saturday, 21 February 2015
Importing an Excel spread sheet with multiple columns
You may have seen it before, but here’s our take:
Case: The end-user has a spreadsheet they want to
import, and creating a csv-file is not an option.
Challenge: In Excel the end user needs to set a “ ’ ”
in front of the numbers if they are to behave as strings e.g. an account no
“123435”. When read in AX the value will be read as 123.435,0000 since is
interpreted as a real. To overcome this, the end user must set the ‘ in front
of the string e.g. ‘123435. Since there may be several hundred or thousands of
records, it is not an option for the end user.
How to import from Excel and format the cells’ content
when assigning to variables in AX.
Suggested solution below:
So, you create a dialog etc. for the file import and
in the actual method you read the sheet, the code looks like this:
private void readExcelFile()
{
SysExcelApplication
application;
SysExcelWorkbooks
workbooks;
SysExcelWorkbook workbook;
SysExcelWorksheets
worksheets;
SysExcelWorksheet
worksheet;
SysExcelCells
cells;
COMVariantType type;
COMVariant
variant;
int
row=1,errors = 0;
smmBusRelTable
smmBusRelTable;
smmBusRelAccount
smmBusRelAccount;
XXX_SortingId
sortingId;
container
errorCon;
;
application = SysExcelApplication::construct();
workbooks = application.workbooks();
ttsBegin;
try
{
workbooks.open(filenameopen);
}
catch
(Exception::Error)
{
throw
error("@SYS19358.");
}
workbook = workbooks.item(1);
worksheets = workbook.worksheets();
worksheet = worksheets.itemFromNum(1);
cells =
worksheet.cells();
type = cells.item(row+1,1).value().variantType();
while
(type != COMVariantType::VT_EMPTY)
{
row++;
//
find variant of cell
variant = cells.item(row, 1).value();
//
set variant type to smmBusRelAccount
smmBusRelAccount =
this.variant2str(variant);
if(smmBusRelAccount)
{
smmBusRelTable = smmBusRelTable::find(smmBusRelAccount,true);
// if there is a prospect proceed
if(smmBusRelTable.RecId)
{
variant = cells.item(row, 3).value();
sortingId = this.variant2str(variant);
if(!sortingId)
{
sortingId = cells.item(row, 3).value().toString();
}
if(XXX_Table::exist(sortingId,8))
{
smmBusRelTable.XXX_Field =
sortingId;
smmBusRelTable.update();
}
else
{
errorCon = conIns(errorCon,maxInt(),strFmt("Error with sorting %1",row,sortingId));
}
}
// write to error log
else
{
errorcon = conIns(errorCon,maxInt(),strFmt("Error with prospect %1",row));
}
}
type = cells.item(row+1, 1).value().variantType();
}
application.quit();
ttsCommit;
info('Import done');
// Header was counted as
successful import. 1 is substracted from row to reflect that headers should not
count
info(strFmt('Number of items imported %1',(row-1)-conLen(errorCon)));
setprefix(strfmt('@SYS344649',conLen(errorCon)));
while
(errors < conLen(errorCon))
{
errors++;
info(conPeek(errorCon,errors));
}
}
In the
while (type != COMVariantType::VT_EMPTY)
we check if there is something the cell read.
Then you assign the variant of the cell
variant
= cells.item(row, 1).value();
which you then cast to string:
private str variant2str(COMVariant
_variant)
{
str valueStr;
;
switch(_variant.variantType())
{
case
COMVariantType::VT_EMPTY :
valueStr = '';
break;
case
COMVariantType::VT_BSTR :
valueStr = _variant.bStr();
break;
case
COMVariantType::VT_R4 :
case
COMVariantType::VT_R8 :
if(_variant.double())
{
valueStr = num2Str0(_variant.double(),0);
}
break;
default
:
throw error(strfmt("@SYS26908",
_variant.variantType()));
}
return valueStr;
}
Friday, 20 February 2015
Easy steps to create a number sequence in AX2012
Following are steps to create new NumberSequence in Ax 2012
1. Open the NumberSeqModuleXXX (XXX is for the module name e.g. NumberSeqModuleCustomer, NumberSeqModuleHRM etc) class in the Application Object Tree (AOT) and add the following code to the bottom of the loadModule() method:
datatype.parmDatatypeId(extendedTypeNum(YYYY)); //EDT used for number sequence
datatype.parmReferenceHelp("zzzzzzzzzzz");
datatype.parmWizardIsContinuous(false);
datatype.parmWizardIsManual(NoYes::No);
datatype.parmWizardIsChangeDownAllowed(NoYes::Yes);
datatype.parmWizardIsChangeUpAllowed(NoYes::Yes);
datatype.parmWizardHighest(999);
datatype.parmSortField(20);
datatype.addParameterType(
NumberSeqParameterType::DataArea, true, false);
this.create(datatype);
2.Create a new job with following code and run it:
static void NumberSeqLoadAll(Args _args)
{
NumberSeqApplicationModule::loadAll();
}
3.Run the number sequence wizard on the Organization
administration >Common >Number sequences > Number sequences > Generate and click on the Next button. Click on Details for more information. Delete the lines except the desired lines ( lines with your module and reference to your EDT). Click next and finish the wizard.
4.You will find the newly created numberSequence in the respective module's parameters form under numbersequence tab.
In the parameters table(zzzzParameters) in the AOT create the following method:
public server static NumberSequenceReference numRefYYYY()
{
return NumberSeqReference::findReference(extendedTypeNum(YYYY));
}
5.To use the number sequence refer to the following code :
public void initValue()
{
NumberSeq NumSeq;
;
super();
NumSeq = NumberSeq::newGetNum(zzzzParameters::numRefYYYY(),true);
//NumSeq.num(); this will create new numbers.
}
Monday, 16 February 2015
How to redirect/drain user clients in a cluster AOS-setup
It may become necessary to redirect users to a
specific AOS instance even though the client configuration is setup to use a
AOS cluster.
If the redirect is a temporary fix such as setting an AOS-server offline for maintenance instead of editing all axc-client configurations, it is possible
in the user interface to tell an AOS-server to redirect user connection to
other AOS-instances in the cluster quite easily:
Open AX and navigate to the System Administration
module:
In the group Users, open Online users:
On the tab Server Instances confirm that are are 2 or
more AOS-instances connected to the application:
Mark the AOS-instance that you want to redirect from
and press the Reject new clients button, e.g.
A prompt will ask for confirmation, press OK:
Status for the AOS instance will shift to Draining,
which means that connections to the AOS-instance is in the process of drained from the AOS-instance(s).
To allow connections to the AOS-instance again, navigate
to the same form, highlight the redirecting AOS instance and press the “Accept
new clients”.
In this way, we have redirected new connections to an
AOS-cluster away from a specific AOS-instance, without altering the client
configuration.
Subscribe to:
Posts (Atom)