Dimensions are ways to tag each financial transaction so that you later can track and group them in a meaningful way. In this article we will dig deeper into what it is and how we can use them.
1. Business perspective
In the end every financial activity becomes a voucher transaction: every sales, production, invoice and salary.
From a legal perspective we keep track of all voucher transactions with main accounts (listed in the chart of accounts). But this is not enough, dimensions are needed to tag every transaction, so that we later can say that Department X have spent Y and earned Z.
In AX 2012, Main Account is one dimension and we can have unlimited dimensions. Common ones are Business unit and Department, but you can choose Customer or your own implemented dimension.
The dimensions used for each legal entity can be different and can be configured in Ledger setup (General ledger > Setup > Ledger) and Account Structures (General ledger > Setup > Chart of accounts > Configure account structures).
2. Technical terms
- Dimension Attribute is the type of information that is traced. In the image above the attributes are MainAccount, BusinessUnit, Department and ServiceLine.
- Dimension Attribute Value is the value of the attribute. In the image above the values are 140200, 004, 023 and Application Development.
Ledger dimension vs. default dimension
There are many ways to store dimension attribute values. The most common ways are ledger dimensions and default dimensions. This is used for instance in General journal (General ledger > Journals > General journal). The table below will explain it more detailed. Because the label, field names and EDT are not consistant (for its reasons), it is important that you get this right from the beginning, before we continue to elaborate all related concepts.
Terms | Ledger dimension | Default dimension |
Example | | |
Label in forms | Account or Ledger Account | Financial Dimension |
Field name | LedgerDimension | DefaultDimension |
EDT | DimensionDynamicAccount, LedgerDimensionAccount | DimensionDefault |
Referenced table | DimensionAttributeValueCombination | DimensionAttributeValueSet |
Comments | Ledger dimension is an ordered list of dimension attribute values. | Default dimensions unordered set of dimension attribute values. In the scenario of general journal lines, default dimensions are inherited from customers, vendors, journals and so on, all the way to the journal lines, but only if the account type is not Ledger. If the account type is ledger then only ledger dimension is enough. |
Both ledger account and financial dimensions are stored as RecIds referencing to the tables listed above (Referenced table). The string in ledger dimension is a form control that gets the value from DimensionAttributeValueCombination.DisplayValue.
It is important to understand how the dimensions are used and what the differences are. In the final posted voucher only ledger dimension is used. But in the journal lines, default dimensions might be used. If the account type is Ledger then only ledger dimension will be used. But in all other cases Customer, Vendor, Fixed assets, Project and Bank - the default dimension will be used. The default dimensions will be combined with the main account into a ledger dimension. The strength with this is that the default dimensions can be set in the customer level and journal level and inherited to the journal lines.
Important patterns used in ledger dimension:
- Default Account - Ledger Dimension, but with only one dimension attribute value, main account.
- Dynamic Account - Similar to Ledger Dimension but it handles the dynamic usage as in journals. When a journal type is Ledger then it stores Ledger Dimension. But when the ledger type is for instance customer, then the dynamic account will have a lookup for customer accounts instead.
Lesser used terms:
- Dimension Attribute Set - An unordered set for Dimension Attributes.
- Dimension Set - Similar to Ledger Dimension but without requirement of Main Account. Mainly used for reports.
3. Data Model
There are a lot of tables that involves dimension. In this section we will focus on a few important ones and how we can use these.
Get display value from LedgerJournalTrans
In the table LedgerJournalTrans, the ledger dimension is stored as a RecId reference. To get the display value you need to get it from DimensionAttributeValueCombination.
static DimensionDisplayValue getDisplayValue(LedgerJournalTrans _transaction)
{
DimensionAttributeValueCombination combination;
;
select DisplayValue from combination
where combination.recId == _transaction.LedgerDimension;
return combination.DisplayValue;
}
Get specific attribute from a combination
This can be useful for instance in a reporting situation where you need to extract the BusinessUnit. In the example below we assume that you have used the previous code to get the DimensionAttributeValueCombination already.
static DimensionDisplayValue getAttributeValueFromCombination(
DimensionAttributeValueCombination _combination,
Name _attributeName = 'BusinessUnit')
{
DimensionAttributeLevelValueView valueView;
DimensionAttribute attribute = DimensionAttribute::findByName(_attributeName);
;
select DisplayValue from valueView
where valueView.ValueCombinationRecId == _combination.recId
&& valueView.DimensionAttribute == attribute.RecId;
return valueView.DisplayValue;
}
Get main account from a combination
static AccountName getMainAccountFromCombination(
DimensionAttributeValueCombination _combination)
{
MainAccount mainAccount;
;
select mainAccount where mainAccount.RecId == _combination.MainAccount;
return mainAccount.MainAccountId;
}
Get specific attribute from customer
static DimensionDisplayValue getAttributeValueFromCustomer(
CustTable _custTable,
Name _attribute = 'BusinessUnit')
{
DimensionAttribute attribute = DimensionAttribute::findByName(_attribute);
DimensionAttributeValueSetItemView valueSetItemView;
;
select DisplayValue from valueSetItemView
where valueSetItemView.DimensionAttributeValueSet == _custTable.DefaultDimension
&& valueSetItemView.DimensionAttribute == attribute.RecId;
return valueSetItemView.DisplayValue;
}
4. Service class for integration
The are many service classes that can be used to handle the dimensions. These classes can be used from both X++, C# using proxies and through AIF. Very useful in other words. The first time to use them might take some time but once you recognize the pattern it is not difficult to guess how to utilize them. The code below is one example for creating a dimension attribute value.
DimensionValueService service = new DimensionValueService();
DimensionValueContract contract = new DimensionValueContract();
;
contract.parmDimensionAttribute('Department');
contract.parmValue('HR')
contract.parmDescription('Human Resources');
service.createDimensionValue(contract);
Because the service classes can be used in both AIF and in code so easily. I recommend that you at least read through the following list at least once, so that you remember to use them when the opportunity arises. Notice that this is not a complete list of all service classes and methods, but a chosen few that believe are useful.
ChartOfAccountsService
createMainAcccount(MainAccountContract _contract)
getLedgerChartOfAccounts()
getLedgers()
getMainAccounts(LedgerChartOfAccountContract _ contract)
DimensionService
getListDimensionsAll()
getDimensions(AccountStructureContract _contract)
DimensionValueService
createDimensionValue(DimensionValueContract _contract)
getDimensionValues(DimensionContract _contract)
FinancialDimensionValidationService
validateLedgerAccount(LedgerValidationContract _contract)
FinancialDimensionBalanceService
getBalance(DimensionSetContract _contract)
5. Useful classes
If you can't find your solution in the service classes the following classes will probably do that.
- DimensionStorage
- DimensionDefaultingEngine
- DimensionDefaultingService
- DimensionAttributeValueSetStorage
For instance we can use this to create a LedgerDimension in this way:
public static LedgerDimensionAccount createLedgerDimension(
MainAccountNum _mainAccountId,
Name _accountStructureName,
Name _businessUnit,
Name _department)
{
MainAccount mainAccount;
DimensionHierarchy hierarchy;
DimensionAttributeValueSetStorage storage = new DimensionAttributeValueSetStorage();
;
mainAccount = MainAccount::findByMainAccountId(_mainAccountId);
hierarchy = DimensionHierarchy::findByTypeAndName(
DimensionHierarchyType::AccountStructure, _accountStructureName);
storage.addItem(DimensionAttributeValue::findByDimensionAttributeAndValue(
DimensionAttribute::findByName('BusinessUnit'), _businessUnit));
storage.addItem(DimensionAttributeValue::findByDimensionAttributeAndValue(
DimensionAttribute::findByName('Department'), _department));
return DimensionDefaultingEngine::getLedgerDimensionFromAccountAndDim(
mainAccount.RecId, hierarchy.RecId, storage.save());
}
6. Creating a new dimension attribute
Creating a new dimension attribute is very simple. First create new view called DimAttribute<name>, in this example we create DimAttributePartyTable. Add the table, and three fields: Key (PartyTable.recId), Value (PartyTable.PartyId) and Name (PartyTable.Name)
Notice that for Value only 30 chars will get stored. So in the case for PartyTable the PartyId will get truncated if we don't shorten the PartyId EDT. Also the Name field is limited to 60 chars. But truncated names are lesser sensitive than the Value.
After refreshing the cache (Tools > Cache > Refresh Elements). We can add the new attribute to a structure. In the form
Configure account structures click the
Add segment you will see your new dimension attribute.
Source : http://axmasterclass.com/blog/financial-dimensions-deep-dive/