Monday, December 28, 2009

How to prompt a user with a query window

This seems pretty straight forward but I've been asked it a few times so I'll write about it: "How can I display an interactive query window to the user in code that looks like the Advanced Query Tool?"

This can be done by taking the QueryRun value and running its method queryRun.prompt() which will return a Boolean value. If the user hits enter, the returned value will be true. If the user cancels out, the value will be false. For this reason, we would want to put this prompt in an if block:

Query query = new Query();
QueryBuildDataSource qbds;
QueryRun queryRun;

qbds = query.addDataSource(tableNum(CustTransOpen));
qbds.addRange(fieldNum(CustTransOpen, AccountNum));

queryRun = new QueryRun(query);

if (queryRun.prompt())
     // Run code

Wednesday, December 2, 2009

Making independent Form Controls Mandatory or changing labels in code: AX 2009

Here is a quick code snippet to access some features of AX form controls that are not too obvious to get to.
In order to have total access to change whatever you want to AX form controls that are either tied to Datasources or just floating on their own to a form (like a filter), you have to grab the control from the form and set it equal to a form control variable.
In the example below, it is FormStringControl. This is helpful for making something like a combo box that is standalone in the form (like a filter).

FormStringControl formControl;
formControl ='NameOfField');
formControl.label("New Dynamic Runtime label");

You can also use control specific types like FormComboBoxControl but combo boxes are strings and the strings give you more options. Just remember that making a base enum could be a problem as default values for some of these are 0 which is a valid value. Only enums with a starting value of 1 would benefit from something like this as 0 would be an invalid value.

Thursday, October 22, 2009

AX 2009 Settlement of Invoice and Payments (AR)

AX 2009 settles Invoices and Payments by Customer account.

This is all high level btw so take it for what it is. It's not meant to be a end all be all of this. Just a good reference to understand how it all fits together.

The functionality for settling transactions can be done by looking at the Clicked method on the CustOpenTrans's Update Now button. It makes a call to CustTrans::settleTransacti(CustTable) where custTable is the customer that needs the settlements done.

A limitation of AX is to not allow the user to specifically point the marked payments/invoices to each other. It instead goes on a first in first out type settlement process based on the transactions that are marked. A modification would be needed for this functionality.

This is why the only thing that is needed is the customer table record. It will use the CustTable record's SpecTrans records for determining which records to try to settle (SpecTransRecId field).

Ultimately, all fun happens in the Class CustVendSettle's SettleNow method. This class is very large and does the actual 'settlement' logic.

As of AX 2009 SP1, this is how the method works:

1st parameter - The settling is done one company at a time

2nd parameter – The table Id of what we are settling (e.g. CustTable).

3rd parameter – The rec Id of what we are settling (e.g. CustTable record).

4th parameter – Boolean. Defaults to true. If true, handles the posting profile difference for the debit and credit transaction and also adjust tax on prepayment transactions. Value becomes negligible if the transaction is a prepayment (both Credit and Debit types).

Financial assistance: Invoices are Debits, Payments are Credits

The whole process will grab the first marked invoice (debit) transaction to settle based on what was marked. It will then grab the first marked payment (credit). When a transaction is marked through the open transaction editing form, it will create a specTrans record which ties to that customer and the respective open transaction. The specTrans record is grabbed based on three criteria:

  1. Company (SpecTrans.SpecCompany)
    1. Value is from 1st parameter of the settleNow method
  2. Table Id (SpecTrans.SpecTableId)
    1. Value is from 1st parameter of the settleNow method
  3. Rec Id (SpecTrans.SpecRecId)
    1. Value is from 1st parameter of the settleNow method

They link this record 1:1 to a record that has the same criteria on the table 'CustVendTransOpen'

It will grab the remaining debit amount from the open debit transaction.

The debit and credit records will only be processed if both the debit and credit side of things are not done (still open transactions to settle against). It will not process is there is a credit transaction left and not a debit. Both must be there.

This is where all the actual posting/financial fun happens. I am omitting it is there is a lot and this entry is not going into detail about that stuff. This is only about the processing of the marked transactions for settling at a high level.

After the process has determined that all of the transactions have marked against each other, it will process the transactions that still have a balance after the settlement. If the unsettled amount is under the set limit, under/over transactions are created.

The whole process ends by calling the method. It then deletes the SpecTrans records even though I think they are already gone at this point.

If you have questions or corrections, feel free to add them in the comments. Hope this helps out!

Thursday, September 17, 2009

Too Many Forms Open…. error

This is a common one I see from a lot of high volume customers. When certain people open a lot of forms consecutively, they will see an error that says "Too many forms are currently open, close some forms and try again" and will crash their client session. This happens due to a restriction of GDI objects that are allowed to be consumed for a given process (10000 objects by default).

ABOUT GDI OBJECTS: This value is controlled at the operating system level and is set in the registry: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\GDIProcessHandleQuota. There is a theoretical limit of 65,536 GDI handles per session. However, the maximum number of GDI handles that can be opened per session is usually lower, since it is affected by available memory. This value can be set to a number between 256 and 65,536. GDI handles are a kernel memory paged pool resource. If you run out of paged pool memory, Windows will start to do some 'quirky' things and become very unpredictable. You are able to tune the GDI limits but be very cautious when doing it.

HOW TO ADDRESS THE AX ISSUE: Due to an issue in Dynamics AX 2009 RTM and SP1, the GDI handles leak in the system which causes the number of GDI objects to rise. This eventually leads to the 10000 (or whatever your value may be) to be reached. This issue is addressed through the KB Article hotfix 960849. It can be found through either PartnerSource or CustomerSource. If the current situation does not allow for a hotfix to be installed, the following are 2 options that can be taken as a workaround:

  1. Restart the Client AX session and reopen it. This resets the GDI handles.
  2. Make sure the users encountering the issue have the 'Filter By Grid On By Default' unchecked in their user options (see Figure 1 below). This will disable the object leak.

Figure 1 - User options screen with 'Filter By Grid On By Default' check box displayed