Creating LedgerDimension from DefaultDimension in D365F&O

 

Its a very common requirement to create ledgerDimension, based on DefaultDimension. Generally we have a habit of hardcoding the dimension names, to get the resulting ledgerDimension value: ex --

 dimensionMap.insert('CostCenter', '0033501_036');
        
 dimensionMap.insert('Location', '2023GBG');
Where CostCenter, Location, Purpose, etc. are various financial dimensions. 
But wouldn't it have been great, if we could generalize the code, so as to eliminate dimension names hardcodes, so that if tomorrow the client decides to include more dimensions, edit or remove some of them, we don't have to change our code?
This article can give you a very handy code to do the same. All you need to do is to call it correctly 😊

I have created a class separately: DimDimensionHelper.
The following method has been added:
public static Map getDimensionWiseDimensionValues_DefaultDimension(DimensionDefault _dimensionDefault)
    {
        Map dimMap = new Map(Types::String, Types::String);
        
        DEFAULTDIMENSIONVIEW defaultDimensionView;

        while select Name, DisplayValue from defaultDimensionView
            where defaultDimensionView.DefaultDimension == _dimensionDefault
        {
            dimMap.insert(defaultDimensionView.Name, defaultDimensionView.DisplayValue);
        }

        return dimMap;
    }
Here you are  passing the DefaultDimension as a parameter, and then looping through the DefaultDimensionView view, and loading up the dimension name and displayValue as key-value pairs in a map.

Next we will pass on this Map along with the main account to create the segmented entry structure: 

public static DimensionDynamicAccount getLedgerDimension(MainAccount    _mainAccount, Map _conData)
    {
        
        DimensionDynamicAccount ledgerRecId;
        DimensionAttribute      dimensionAttribute;
        DimensionAttributeValue dimensionAttributeValue;
        DimensionSetSegmentName DimensionSet;
        DimensionStorage        dimStorage;
        LedgerAccountContract   ledgerAccountContract = new LedgerAccountContract();
        DimensionAttributeValueContract ValueContract;
        List valueContracts = new List(Types::Class);
        dimensionAttributeValueCombination dimensionAttributeValueCombination;
        MapEnumerator           mapEnum = _conData.getEnumerator();
 
        
        while (mapEnum.moveNext())
        {
            
            dimensionAttribute = DimensionAttribute::findByLocalizedName(mapEnum.currentKey(),false, CompanyInfo::find().LanguageId);
 
            if(dimensionAttribute)
            {
                dimensionAttributeValue = DimensionAttributeValue::findByDimensionAttributeAndValue(dimensionAttribute, mapEnum.currentValue());
                if(dimensionAttributeValue)
                {
                    ValueContract = new DimensionAttributeValueContract();
                    ValueContract.parmName(dimensionAttribute.Name) ;
                    ValueContract.parmValue(dimensionAttributeValue.CachedDisplayValue);
                    valueContracts.addEnd(ValueContract);
                }
            }
        }
        ledgerAccountContract.parmMainAccount(_mainAccount.MainAccountId);
        ledgerAccountContract.parmValues(valueContracts);
        dimStorage = DimensionServiceProvider::buildDimensionStorageForLedgerAccount(LedgerAccountContract);
        dimensionAttributeValueCombination = DimensionAttributeValueCombination::find(dimStorage.save());
        ledgerRecId = dimensionAttributeValueCombination.RecId;
        return ledgerRecId;
    }
Here its essentially looping through the map's key-value pair, and getting each and every dimension name, searching in the hierarchy. If a match is found, its trying to search the associated value pair and then loading in a list called 'ValueContracts'. Rest is very simple -- as we all know -- using DimensionStorageProvider to create a the dimensionValueCombination recId, and then sending it back to calling code.
Summing it up, here is how, you can call the above methods:
Map dimension = DimDimensionHelper::getDimensionWiseDimensionValues_DefaultDimension(_dimensionDefault);
ledgerDimaccount = DimDimensionHelper::getLedgerDimension(mainAccount, dimension);
transJournal.LedgerDimension          = ledgerDimaccount;

Hope it helps 😊 

Comments

Popular posts from this blog

X++ : mistakes which developers commit the most

Make your menu items visible on main menu, conditionally,, using this cool feature of D365FO

Speed up your execution performance by using SysGlobalCaches