28 June 2017

Bug: SysFormEnumComboBox selection method returns wrong value

The SysFormEnumComboBox class is very useful when only some of enum values must be enabled in a form, but it has a bug.

Problem description
The SysFormEnumComboBox.selection() method returns correct value only when being called after super() of form run method.
Test form is attached.
In form init method SysFormEnumComboBox is initialised with 3 enum values, Invoiced value is set as default and selection method is called:

In form run method selection method is called before and after super():

The results are:
init method, after super, SalesStatus selection is 255.
run method, before super, SalesStatus selection is 255.
run method, after super, SalesStatus selection is 3.

Hints
It appeared that FormComboBoxControl texts are set in form run method. Alternative approach must be used to get enum selection.

29 May 2017

Top overridden form methods in AX 2012 R3

Today I am going to analyse form and datasource methods in standard AX application and find the most and the least overridden.

Form
Overridden rate is calculated as the ratio of the number of forms, where a method is overridden, to the total number of forms.
What does the diagram say?
Not surprisingly, init method is almost always overridden. run, close and closeOk methods are often overridden. All other methods are rarely overridden.
The following methods are never overridden in standard application:
addHistory
blockPersonalization
closedCancel
controlMethodOverloadObject
copy
getActiveWorkflowConfiguration
getActiveWorkflowTrackingStatus
getActiveWorkflowWorkItem
initWorkflowControls
loadUserSetting
reload
send
setApply
skipSaveUserSetting
updateWorkflowControls


Datasource
Overridden rate is calculated as the ratio of the number of datasources, where a method is overridden, to the total number of datasources.

Top overridden methods are:
init, active, executeQuery, write, validateWrite, initValue, delete, linkActive, create.
All other methods are rarely overridden.
The following methods are never overridden in standard application:
defaultMark
findValue
markAllLoadedRecords
refreshEx


Conclusion
This standard application statistics reflects what is usually overridden by a developer on a regular project:
- init, run, close methods on a form
- init, active, executeQuery, write methods on a form datasource.

10 April 2017

Specifics of update_recordset crossCompany in AX 2012

Have you ever tried to run update_recordset crossCompany statement?
Yes, it is possible. There are only 5 methods in standard AX code with such statement, but it can be very useful for data update jobs in multi company environment.

Tables:
TaxTransGeneralJournalAccountEntry.moveTaxForeignKeyToTaxTrans()
RetailLoyaltyConflictCard.migrateConflictCards()

Classes:
ReqDemPlanForecastChangeTracker.applyAllChanges()
ReleaseUpdateDB63_HRMMinor.updatePositionForecastBudgetAcctLine()
ReleaseUpdateDB63_HRMMinor.updatePositionForecastCompGroupRefPoint()

You must disable update method, database log and alerts, otherwise compiler will throw an error, for example:
transTable.skipDataMethods(true);
transTable.skipDatabaseLog(true);
transTable.skipEvents(true);
update_recordSet crossCompany transTable
setting loyaltyCardId = conflictCard.NewCardNumber
    where transTable.loyaltyCardId == conflictCard.CardNumber
       && transTable.dataAreaId == conflictCard.Company;
If you are still not convinced, then there is another example below.

27 March 2017

What is wrong: crossCompany update job in AX 2012

I want to challenge you today to find an error in the following update job. Do not pay attention to the functional part. I agree, the job can be rewritten, but let's assume it must be done this way.
static void crossCompanyUpdate(Args _args)
{
    CustTable   custTable;
    CustGroup   custGroup;
    PaymTermId  oldPaymTermId = 'Net10', newPaymTermId = 'Net11';
    
    ttsBegin;

    // find all companies with oldPaymTermId
    while select crossCompany custGroup
        group by custGroup.dataAreaId
        where custGroup.PaymTermId == oldPaymTermId
    {
        changeCompany(custGroup.dataAreaId)
        {
            // disable update method
            custTable.skipDataMethods(true);

            // set newPaymTermId
            update_recordSet crossCompany custTable
                setting PaymTermId = newPaymTermId
                where custTable.PaymTermId == oldPaymTermId;
        }
    }

    ttsCommit;
}
Post your ideas into comments. I will open comments and post my solution in one week. Have fun :-)

Solution
There is no compile or runtime error, but records are updated only in one company. Table variable must be set to null within changeCompany statement, marked in orange below:
static void crossCompanyUpdate(Args _args)
{
    CustTable   custTable;
    CustGroup   custGroup;
    PaymTermId  oldPaymTermId = 'Net10', newPaymTermId = 'Net11';
    
    ttsBegin;

    // find all companies with oldPaymTermId
    while select crossCompany custGroup
        group by custGroup.dataAreaId
        where custGroup.PaymTermId == oldPaymTermId
    {
        changeCompany(custGroup.dataAreaId)
        {
            custTable = null;

            // disable update method
            custTable.skipDataMethods(true);

            // set newPaymTermId
            update_recordSet crossCompany custTable
                setting PaymTermId = newPaymTermId
                where custTable.PaymTermId == oldPaymTermId;
        }
    }

    ttsCommit;
}

09 February 2017

Simply about applyTimeZoneOffset and removeTimeZoneOffset methods of DateTimeUtil

In this post I want to describe simple rules of working with an unbound UtcDateTimeEdit control in a form:
1) from the database to the user -> applyTimeZoneOffset
2) from the user to the database -> removeTimeZoneOffset
Continue reading for the details.

Problem description
Define how to set and store value of an unbound UtcDateTimeEdit control in a form.

Hints
Play with bound and unbound UtcDateTimeEdit controls in a form.

30 January 2017

How to copy cross-reference from one environment to another

Cross-reference is a very useful tool in Dynamics AX, but cross-reference update requires a lot of time and resources. I want to share a simple way to copy cross-reference data.

Problem description
Copy cross-reference from one development environment to another, provided environments are identical.

Hints
Use bcp utility for export and import.

26 December 2016

How EntireTable cache works in AX2012 R3

The description of EntireTable cache on msdn seems ambiguous. On the one hand, all the records in the table are placed in the cache after the first select. On the other hand, the SELECT statement WHERE clause must include equality tests on all fields of the unique index. Let's run several tests to analyse it.

Problem description
Analyse how EntireTable cache works by tracing T-SQL statements and using wasCached method.

Hints
Run select statements with and without where clause on server and client.