Thursday, January 09, 2014

AX2012 R2 CU7 DIEF/DIXF LedgerDimension import error - Financial dimension value does not exist.

AX2012 R2 CU7 have Dimension Import Export Framework bundled and it's has fixed some bugs and added new default entities over the previous version. Bugs still exists though -_-'. This time I came across an error saying Financial Dimension value <value> does not exists when I try to import data using the Opening Balance entity.

How to reproduce:
- Use Dynamics AX Demo database (USMF).
- Create a Text source data format. Set the DimensionAttribute as BusinessUnit-CostCenter-Department
- Create a processing group. Add Opening Balance Entity in it. Then create an entity in the group that use the above source data format.
- Generate a source file.
- In the source file, entered a transaction where money is debited from a bank account (110110) to the petty cash account (110180). (Please forgive me if this transaction doesn't make real world sense. =])

Here's what I put for the LedgerDimension and the OffsetLedgerDimension field:
LedgerDimension (110110-001--)
OffsetLedgerDimension (110180-001-007-022)

Import to staging database is fine, but when you try to push to Target there is an error: Financial dimension value 007 does not exist.

What happened?
During the process, AX get the list of dimension attribute from system settings. In this case, for the 110xxx account, the active Dimension Attributes are BusinessUnit and Department only. So it looks like [MainAccount,BusinessUnit,Department]. AX also look at the Dimension Values we imported, for our OffsetLedgerDimesnion, it's [110180-001-007-022].

So we have 3 items in the Dimension Attributes list and 4 items in the Dimension values list. In this particular example, the Dimension Values does not exists error was generated because of this. 
When I look at the code, it seems to expect a matching set of Dimension Attributes and Dimension Values. 

How to fix it? 
Now the fun part. The fix mention below tackle particularly the case of Opening Balance Entity. However, it can be used with other entities easily with minimal effort if you encounter this error dealing with other entities. 

Go to \Classes\DMFDimensionHelper\generateDynamicDimension method, add a 3rd parameter DMFDataSourceProperties.
                
public static RecId generateDynamicDimension(Str dimValueString,
        SelectableDataArea      _dataArea = curext(),        
        DMFDataSourceProperties _properties = null     // New parameter added
        )

Then below the standard code where dimAttributeList is populated. Add the following code.
                
// If DMFDataSourceProperties availabe, use its dimensionAttribute value to overwrite the dimAttributeList.
    if (_properties != null)
    {
        dimAttributeList = str2con(_properties.DimensionAttribute,     
                                   enum2str(_properties.ChartOfAccountsDelimiter));
        dimAttributeList = conIns(dimAttributeList, 1, 
                                  DimensionAttribute::find(
                                       DimensionAttribute::getMainAccountDimensionAttribute()).Name);
    }      

Finally, pass in the DMFDataSourceProperties from the DMFLedgerBalanceEntityClass. In the GenerateLedgerDimension and GenerateLedgerOffsetDimension method, edit the call to DMFDimensionHelper::generateDynamicDimension() method by adding the dmfDataSourcePropertiesGlobal at the end. For example, in GenerateLedgerDimension method:
else
{
    target.LedgerDimension =  DMFDimensionHelper::generateDynamicDimension( 
                                             entity.LedgerDimension, 
                                             entity.Company, 
                                         // Add the third parameter here
                                             dmfDataSourcePropertiesGlobal);
}

Good luck, have fun. =D

 
This posting is provided "AS IS" with no warranties, and confers no rights.

Tuesday, January 07, 2014

AX2012 R2 RunAs and Global::RunClassMethodIL

Just a quick note on using RunAs in AX2012: The static method being called by RunAs should have a container parameter in the method declaration. Otherwise, system will complain that the static method was not found. So:
                
// This would fail with static method not found error.
public static void methodWithoutParm()
{
}

// This would work!
public static void methodWithContainerParm(container _c)
{
}
In fact, the same can be said to Global::RunClassMethodIL. However, the error throw by Global::RunClassMethodIL is more helpful. It'll complain that the parameter passed into the static method is incorrect. Seeing that a third parameter of type container is mandatory for Global::RunClassMethodIL, it's easier to get the idea to try adding the container parameter in the target static method. =]
This posting is provided "AS IS" with no warranties, and confers no rights.