One of my initial programming tasks with Dynamics 365 for Operations (AX 7) has been writing routines to import data from external systems. These complex routines are writing to multiple tables, and sending email when there are problems (a subject for a future post)… and, recently, took another step up in complexity.
When I found out I had to write a routine to import data to “Financial Dimensions” (sometimes called “Default Dimensions” for reasons I’ll soon explain) on employees/workers (more specifically, their employment records, the HcmEmployment table) I was flummoxed for a while.
It took me a bit of reading to figure out what Financial Dimensions even were. Basically, they are attribute/value pairs that you can define yourself. There is more to them then that, and I won’t say I fully understand them yet… that’s a subject for other posts, so I’m just giving you some basics here in case you are unfamiliar. A few are set up by default, but you can also create your own. (General ledger > Chart of accounts > Dimensions > Financial dimensions) So you or an admin can go create a Favorite_Color dimension, give it a bunch of choices (01=Red, 02=Blue, etc.) and then attach a favorite color to a bunch of entities. Just look for a DefaultDimension column. Once that’s done, users can see and set them. For example, in my case, I could go to Human resources > Workers > Worker, look under “Employment” for a given worker, and see the Financial dimensions section listed at the bottom.
Unfortunately, the way they are stored and managed is complex. It’ll take a bunch of reading and looking at code samples to figure out how to get data out of them; I won’t repeat that here, it’s easy to find. But for all my searching, I could not find a way to WRITE to financial dimensions in X++. Finally, with a little help (thanks to Steeve Gilbert in the AXUG forums), I was able top work out a reusable method (or three) to help.
I’m sharing my sample code here to save you the pain I experienced. For sake of example, I’m assuming you put this in a class named MyDimensionHandlerClass, along with any other generic/reusable dimension-related methods you want.
In future blog posts I will share sample code for reading and validating attributes, just for completeness… although there are other samples for those out there.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /// <summary> | |
| /// Generic dimension updater. Call this with the DefaultDimension of any table, and update that table’s DefaultDimension with the returned value. | |
| /// | |
| /// Sample usage: | |
| /// hcmEmployment.DefaultDimension = xczDimensionHandler::PutDimension(hcmEmployment.DefaultDimension, ‘Favorite_Color’, ’01’); | |
| /// hcmEmployment.validTimeStateUpdateMode(ValidTimeStateUpdate::Correction); // This may or may not be appropriate for your circumstances | |
| /// hcmEmployment.update(); | |
| /// | |
| /// Based on sample code courtesy Steeve Gilbert. | |
| /// </summary> | |
| /// <param name = "_DimensionAttributeValueSet">Value in the "DefaultDimension" column of the linked table (i.e. HcmEmployee, etc.). Links to DimensionAttributeValueSet.RecId. You will need to update the calling table this came from.</param> | |
| /// <param name="_attribute">Attribute (e.g. "Department").</param> | |
| /// <param name="_value">Potential value for the Attribute (e.g. "950").</param> | |
| public static RecId PutDimension (RecId _defaultDimension, str _attribute, str _value) | |
| { | |
| DimensionAttribute dimAttribute; | |
| DimensionAttributeValue dimAttributeValue; | |
| DimensionAttributeValueSetStorage dimStorage; | |
| // Verify that the value passed for _attribute identifies a real dimension. | |
| select firstonly dimAttribute | |
| where (dimAttribute.Name == _attribute); | |
| if (!dimAttribute) | |
| { | |
| throw error(“Invalid _attribute passed to PutDimension: ” + _attribute); | |
| } | |
| // Find or create a storage dimension that contains each dimension attribute and their value. | |
| dimStorage = DimensionAttributeValueSetStorage::find(_defaultDimension); | |
| // Update or delete the value within that storage dimension. | |
| if (_value) | |
| { | |
| dimAttributeValue = DimensionAttributeValue::findByDimensionAttributeAndValue(dimAttribute, _value, true, true); | |
| dimStorage.addItem(dimAttributeValue); | |
| } | |
| else | |
| { | |
| //If there’s no value, that means we want to remove that Dimension Attribute | |
| dimStorage.removeDimensionAttribute(dimAttribute.RecId); | |
| } | |
| return dimStorage.save(); | |
| } |
