Friday, August 16, 2013

The str2num function and decimal numbers

There seems to be an issue with the str2num function when what you want is a real value. This matters because it can be used to convert from a string to an int or a real.

In order to successfully convert from a string representation of a decimal value to an actual real type on X++, you can't have any formats on your string. That means that the string has to be representing a double exactly as the real variable does: no thousand separator, and the dot ('.') character for the decimal separator.
It does not consider AX's region when performing the conversion.

Consider the following job:

static void Job1(Args _args)
    str val1, val2, val3, val4;
    real real1, real2, real3, real4;
    val1 = '100,000.000';
    val2 = '100.000,000';
    val3 = '100000,005';
    val4 = '100000.056405';        
    real1 = str2num(val1);
    real2 = str2num(val2);
    real3 = str2num(val3);
    real4 = str2num(val4);

The only valid conversion is the last one, from the variable val4. The real variables have the following values after the assignment:

So just remember to be very careful when converting from a string representing a decimal value to a real X++ type when using the str2num function.

You can always use the .NET Framework instead. If you do, then you'll be able to set a specific culture when converting the double value, like the following valid X++ code:

System.Globalization.CultureInfo cultureInfo = System.Globalization.CultureInfo::CreateSpecificCulture("pt-Br");
    real parsedDouble = System.Double::Parse("1.200,99", cultureInfo);
    print parsedDouble;

Monday, August 12, 2013

Displaying a SysInfoAction button on the Infolog

Actioning it

Have you ever found yourself in a situation where the Infolog keeps throwing up the same error / warning at you and you have no idea how to resolve it?
For example: "The field Foo must be set to Y to perform this action". That's a pretty clear message: you just have to set the Foo field to Y and you're good to proceed with what you were doing, except that you have no idea where the Foo field is! When I started working with AX, I found myself in this situation more than I'd like to, and it always annoyed me to have to call someone and ask where the damn Foo field was.

But sometimes, the Infolog would show me a magic button that would take me exactly to wherever I had to go to fix the error it was showing me. That magic button is called a SysInfoAction. For the example I have given above, if the good guy programmer had put a SysInfoAction on the Infolog, you could just click on a button and a form with the Foo field would pop up.

So how do you do it? Well, there are some different SysInfoAction types. Just to list a few of them:

  • SysInfoAction_CostSheetValidate
  • SysInfoAction_Editor
  • SysInfoAction_Formrun
  • SysInfoAction_MenuFunction
  • SysInfoAction_newWindow
  • SysInfoAction_Properties
  • SysInfoAction_Showplan
  • SysInfoAction_TableField

As you'd expect, each one of these classes exposes a different behavior when the user interacts with the button on the Infolog.

Let's take a look at the SysInfoAction_MenuFunction for example.

It does what the name suggests: adds a menu item on the Infolog. And it can be of any type: Action, Display or Output.

Suppose we want to redirect the user to a form so that he can fill in the "Foo" field:

SysInfoAction_MenuFunction sysInfoAction;

sysInfoAction = SysInfoAction_MenuFunction::newMenuItem(menuitemDisplayStr(FooFormMenuItem), MenuItemType::Display);

warning('The field Foo must be set to Y to perform this action', '', sysInfoAction);

Just by creating that object and passing it to the warning() method, you made the user's life a lot easier. There's also a constructor available to the SysInfoAction_MenuFunction where you can pass in the control's name of the form you're opening, and the framework will set the focus to that control if it's found on the form. Although it helps even more, the call to the method should be ugly, and easy to break, since there is no compile-time checking if the control actually exists on the form.
The good part though is that if the control isn't found, it just doesn't do anything.

But what about security?

I have to say that the security framework team did a tremendous job overall, and it's just the same with the SysInfoAction feature.
The SysInfoAction, in this case, is nothing more than a menu item. Menu items are bound with security objects in various ways, so it's kind of easy to get the related roles or duties. That being said, guess what happens if the user doesn't have the permission to run the MenuItem you have added to the SysInfoAction? The user doesn't see the button.
So if you're worrying that you might accidentally redirect a user to an important parameters form which he shouldn't have access to, don't worry, because you wont: the security framework will take care of that for you.

That all being said, I'd advise to always use SysInfoActions where it really improves the user experience.