Monday, December 21, 2009

How to set the language used on a report

When printing a report, Ax sets the used language automatically based on the user's settings. The selection of available languages for the client interface depends on the installed language license keys.

But sometimes, it may be necessary to change the default settings for reports. With reports needed for external use for example. Like invoices and packings slips you send to your customers. These documents require to be made up in the language of your customer. Ax is designed with this scenario in mind.

The language to use in the report can be set with following command:

element.design().languageID();

So for example:

element.design().languageID('en-us');


Place the code in the init method of your report, or in the fetch method.


You can use this in your own custom reports as well, with no limitation regarding the language license keys you bought. All you need are the appropriate label files. (Otherwise you get error messages like 'label @SYS123 not found in language xyz'.)

Got some time to spare? It can be fun to see how your documents look like in he - Hebrew, with its right to left printing.

Recurring issue: str2num

There is a general problem with string to numeric conversion in Ax, which seems to resurface now and again.
Last time around when we faced this problem, we were working in the Product Builder modules. We had variables setup with default values like this: 3.200,00 mm
But when Ax loaded the configuration form, the string values were converted to 3 (no decimal value setup - values divided by 1000). Ax had interpreted the thousand separator as the decimal separator. It's easy to test:



test=str2num("3.200,00");



As the values stored for the configurated product models are all converted to string values (table PBATableInstance), there are 2 possible approaches to this problem.

1. Make sure the saved value is stored without the thousand separator. ("3200,00" converts ok to 3.200,00)

2. Make sure the retrieved value is converted back to a numeric value in the right way.



We choose the latter approach. We edited Class PBABuildForm\fillDataSource, where the default values of the product model are set up.



pbaTmpBuildForm.Comma = str2num(strrem(pbaTableInstance.Value,'.'));



(Ax 2009 SP1 - no HF)

Use colors in a report

In my last post, I talked about the use of colors in a grid. You can use the discussed example to add some spice to your forms.
But the same can be applied to reports as well. Anyone remembers those old dot matrix printers, with that huge stacks of print paper? The paper had green lines, in order to improve the readability.
You can get the same effect, with almost any report in Ax. This is some coding I did a couple of years ago for a user that complained about his report, saying the characters where "all dancing around on the paper".

Create a static method on a class, for example the Global class. (this way you can reuse this code on multiple reports)

static void SetReportLine(ReportSection _ReportSection)
{ int controlcount;
int counter;

int usecolor;
int oldcolor;

object reportobject;

;
controlcount=_ReportSection.controlCount();

oldcolor=_ReportSection.foregroundColor();

if(oldcolor==WinApi::RGB2int(255,255,255))
usecolor=WinApi::RGB2int(220,255,220);
else
usecolor=WinApi::RGB2int(255,255,255);

_ReportSection.foregroundColor(usecolor);

for(counter=1;counter<=controlcount;counter++) { reportobject=_ReportSection.controlNo(counter); reportobject.backgroundColor(usecolor); } }


Now all you have to do, is call this static method from your report. Call it from the executed section in the report, before the call to super, like this

public void executeSection()
{ ;
Global::SetReportLine(this);

super();
}


The result will look something like this:








Eco tip: Again, don't overdo the use of this effect. As all coloring needs to be printed, ink is used. The darker you color your lines, the more ink gets used. So this tip isn't that eco friendly, as it is retro style.

Saturday, December 19, 2009

How to use color in a grid

How to color records in a grid is a common user request that can be found on the web.


Actually, this is quite simple to achieve in Ax, with only a small modification. The trick is to override the displayOption method on the form's datasource.



Non-overriden, it looks like this:



public void displayOption(Common _record, FormRowDisplayOption _options)
{
super(_record, _options);
}



By using the options object, an object of class FormRowDisplayOption, you can set the background color.



_options.backColor(myColor);





You can use the record information from _record to set any background you want, where each row in the grid can have a different background color.


For that reason, it may be better to change it's type to the specific table used in the datasource.


Like this:





public void displayOption(CustTable _CustTable,FormRowDisplayOption _options)


{ int myColor=WinApi::RGB2int(50,255,50);
;

if(_CustTable.Currency=='EUR')


_options.backColor(myColor);



super(_CustTable, _options);
}



In the example above, we color code our customers in the form CustTable. (Remember: Changes go in the methods of the form's datasource.) Customers with currency EUR get a green color.


The result looks like this:





By using colors, you can enhance the visual representation of your data. Making it easier for users to grab their attention, focusing them on certain data. The data gets processed faster.

Just make sure you don't overdo it, making it hurt your users eyes ;-)

Monday, December 14, 2009

Jubilee!

Oops, missed an anniversary.








Over 50 blog posts (and counting).




So a big thank you to my blog readers, my blog followers and commenters. Much appreciated!




When I started this blog, I wanted to give something back to the Ax community.


When I had questions about Ax in the past, I didn't always find the answer in the manuals. But the web with it's many Ax professionals provided me with answers on many occasions. I hope this blog gives someone out there some answers as well.

How to generate random numbers in Ax

Ax has functionality built-in to generate random numbers. You can use the Random class for this purpose. Like this:

static void RandomGenerator(Args _args)
{ Random Random = new Random();
int myrandomnumber;
;
myrandomnumber=1 + Random.nextInt() MOD 100;
info('Number '+int2str(myrandomnumber));
}

In the above example, Ax will generate a random number in the range from 1 to 100.
Though the random class gives you integer values, you can use it to generate random real values as well.

static void RandomGenerator(Args _args)
{ Random Random = new Random();
real myrandomnumber;
;
myrandomnumber=(1 + Random.nextInt() MOD 1000)/1000;
info('Number '+num2str(myrandomnumber,0,3,1,0));
}

This example generates random numbers in the range 0.001 to 1.000.

The use of this function comes with a warning:
The chosen numbers are not completely random because a definite mathematical algorithm is used to select them but they are sufficiently random for practical purposes.

So, good enough to use in an ERP system.

Saturday, December 5, 2009

Product Builder perfomance tip

With the Product Builder modules from Ax, your users (internal or external) can configure their own products. These products can range from electronic devices (demo company) to basically everything you can imagine.

Loading the form for configuration of the product model can take some time. If you have lots of variables (complex product model), it can take more than 20 seconds. And that's an eternity for some users in this day and age.

So I thought to share this little performance tip with you.

In Ax, setting the properties of a form control can take quite some time. The more variables you have, the more form control properties to set. Think of enabled Yes/No, hidden Yes/No.
Now there's no need to set the property, if it's already set. That's a waste of time. So if a field is already hidden, don't hide it again. If it's enabled, don't enable it again.
But unfortunately, that is exactly what the standard code is doing. But we can change this behaviour: Go the the class PBAFrontEndControl, method SetControlProperties.

Change this part:

dataSource.object(valueTmpBuildForm.activeField()).enabled(enabled);
dataSource.object(valueTmpBuildForm.activeField()).mandatory(mandatory);
dataSource.object(valueTmpBuildForm.activeField()).visible(visible);

into this part:

if(dataSource.object(valueTmpBuildForm.activeField()).enabled()!=enabled)
dataSource.object(valueTmpBuildForm.activeField()).enabled(enabled);
if(dataSource.object(valueTmpBuildForm.activeField()).mandatory()!=mandatory)
dataSource.object(valueTmpBuildForm.activeField()).mandatory(mandatory);
if(dataSource.object(valueTmpBuildForm.activeField()).visible()!=visible)
dataSource.object(valueTmpBuildForm.activeField()).visible(visible);

Similar code can be found in the method with the same name in class PBAFrontEndControlWin.

These small modifications reduced the load time of the form to below 5 seconds for us, where it was first 20 seconds +.

Do you have any performance tips as well? Share them in the comments!