Category Archives: Dynamics AX 2009

Posts about Dynamics AX 2009

Sales line number not unique

There are cases in all current versions of Microsoft Dynamics AX where the line number on sales order lines is not incrementally assigned and can therefore be assigned in duplicates.

For the purpose of the post i have added the field “Linenum” to the grid in the sales order form.

As you can see below the line numbers are assigned incrementally when creating order lines in an ordinary fashion. (one by one).
2016-05-27 10-35-15

Some sellers might decide to add a few empty sales lines to the order before picking the item number like this.
2016-05-27 10-44-41

At this point the line number still looks normal.
But lets see what happens when when we start picking values for these lines and saving them.
2016-05-27 10-48-05

In this example i start by assigning an item number for the last row and then for the first row.
As soon as the item number is assigned and i leave the field, the line number is changed to 3.

The first thing you might ask yourself is: “Why the heck would you create order lines this way?”
That i can’t answer, but i know for sure that it’s not totally uncommon.

If sales line number are not unique you might run in to problems with some customizations that uses the line number to identify the sales line.

Our solution for this is to enforce a more “normal” behavior by adding a piece of code that deletes all cached sales lines every time a sales line is saved.

Simply add this method to the data source “SalesLine” in the form “SalesTable”.

private void HandleMultipleCacheLines()
{
    SalesLine   salesLineLineNum;
    ;
 
    salesLineLineNum = salesLine_ds.getFirst();
 
    while (salesLineLineNum.SalesId)
    {
        if (!salesLineLineNum.RecId)
        {
            salesLine_ds.cacheRemoveRecord(salesLineLineNum);
        }
 
        salesLineLineNum = salesLine_ds.getNext();
    }
 
    salesLine_ds.reread();
    salesLine_ds.refresh();
}

And call the new method from within the method “write” on the data source “SalesLine”.
Put the call right below “super();”.

Please let me know if you have a another solution.

Date and UtcDateTime interval for previous month

This code calculates the first and last date of the previous month.

1
2
3
4
5
6
7
8
9
10
11
12
static void EP_dateMonthInterval(Args _args)
{
    date            fromDate;
    date            toDate;
    date            baseDate = systemDateGet();
    ;
 
    toDate      = dateStartMth(baseDate) - 1;
    fromDate    = dateStartMth(toDate);
 
    info(strFmt("%1 - %2", fromDate, toDate));
}

UtcDateTime version of the same job.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static void EP_UtcdateMonthInterval(Args _args)
{
    UtcDateTime     fromDate;
    UtcDateTime     toDate;
    UtcDateTime     baseDate = DateTimeUtil::utcNow();
    ;
 
    // Remove this month number of days.
    toDate = DateTimeUtil::addDays(
    baseDate, -(DateTimeUtil::day(baseDate) -1));
 
    // Add the rest of this days time minus one second.
    toDate = DateTimeUtil::addSeconds(
    toDate, -(DateTimeUtil::time(toDate)+1));
 
    // Remove the number of days we are on in
    // the previous month and add one second to 
    // get to the first of the month.
    fromDate = DateTimeUtil::addSeconds(
    DateTimeUtil::addDays(
    toDate, -(DateTimeUtil::day(toDate))), 1);
 
    info(strFmt("%1 - %2", fromDate, toDate));
}

Maps and MapEnumerators

This code put five records of the table CustTable in a map with the key AccountNum. Then the map is looped and the and AccountNum and customer Name is printed to the infolog.

The last part of the code finds the last AccountNum from from the loop directly from the Map, but after a check is done if the value is in the map. Performing a lookup for a value that doesn´t exist in map will result in a error.
Continue reading Maps and MapEnumerators

Advanced filter, day/month/year

It’s been a while since the last post but here is a useful tip to improve your filtering in Dynamics AX 2009. Thanks to Filip Carnbäck.

If you need to set an advanced filter on an interval you can use the following:

dayRange
monthRange
yearRange

Use dayRange for example like this: (dayRange(-2,2)) This will filter out all transactions two days before today and two days from today. Use monthRange and yearRange in the same way. This feature is among other useful when you setup a report to print in batch and the filter on date must change for each printout.

Also try these features when you filter:

(greaterThanDate(-2))

(lessThanDate(0))

Example dayRange

No valid document identified from the entity key

I recently encountered this problem while using the AIF framework in Dynamics AX 2009. I got it in the AIF Queue manager when one of my messages failed.
Since the message “No valid document identified from the entity key” doesn´t really give you a good clue of that the problem really is, I had to do some debugging. I found that the error occurred when the class AifConstraintListCollection did not contain any constraints and the message(document) was associated with a query.

Continue reading No valid document identified from the entity key

Using Regular Expressions in Dynamics AX

When working with strings, ex. replacing text, validating content or simply checking for existence, It can sometimes be a good idea to consider using Regular Expressions (RegExp), insted of using ordinary string manipulation methods.

X++ itself does not seem to support Regular Expressions, but we can use the .NET functionality.

Below is an example method of how to validate that an email address is written in a proper format.

1
2
3
4
5
6
7
8
9
10
11
Static Server boolean validateEmail(EMail   _eMail)
{
    Str MatchEmailPattern =
    @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$";
    System.Text.RegularExpressions.Match myMatch;
    ;
 
    myMatch = System.Text.RegularExpressions.Regex::Match(
    _eMail, MatchEmailPattern);
    return(myMatch.get_Success());
}

It simply returns true if the input is a properly formatted email.

To replace text in a string you could do something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static void Job1(Args _args)
{
    Str EmailPattern =
    @"\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b";
    Str ReplacedText;
    ;
 
    ReplacedText =
    System.Text.RegularExpressions.Regex::Replace(
    "My email address is: example@haxx.net",
    MatchEmailPattern,"blabla@haxx.net");
 
    print ReplacedText;
    pause;
 
}

This will replace ALL found email addresses.

Below is an example of how to “find” all matches.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static void Job6(Args _args)
{
    Str MatchEmailPattern =
    @"\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b";
    System.Text.RegularExpressions.Match myMatch;
    ;
 
    myMatch = System.Text.RegularExpressions.Regex::Match(
    "Your email: youremail@host.net, and my"
    +"email: myemail@anotherhost.com", MatchEmailPattern);
 
    while (myMatch.get_Success())
    {
        print myMatch.get_Value();
        myMatch = myMatch.NextMatch();
    }
 
    pause;
}

Notice the difference between the RegExp pattern in this example and the first example.

The first pattern checks if the input is valid.

And this pattern checks for ALL valid matches.

For more information about regular expressions visit:
www.regular-expressions.info

AIF – Wrong field ID in the key data container in entity key

@SYS92355 = “Wrong field ID in the key data container in entity key”

This error message from the AIF in AX4sp2 did give me some headache today..

Finally I solved it. I was about to export a SalesOrder with both header and lines, but I did put my sendElectronically method in the SalesLine table, *not* in SalesTable table.. So when executed I never got the correct keys. The query I used for the axd wizard was based on SalesTable first, and THEN SalesLine..

Might help someone else with the same or similar problem!