RSS

AX Mobile Applications–Solugenix Corporation

Hi Friends,

Solugenix Corporation is involved in developing some easy to use mobile applications for AX. For more details, check this link out:

http://sandeepchaudhury.wordpress.com/2012/02/11/mobile-applications-from-solugenix-for-microsoft-dynamics-ax/

 
Leave a comment

Posted by on February 15, 2012 in Uncategorized

 

AOT Resources in Image Options [AX 2012]

Till AX 2009 there was only one way for us to use the AOT resources for specifying on menus or menu items or buttons and that was using SysResources class and call while application start to set in various places. But with this small change in Ax 2012, MS has provided a very good small change to use AOT resources in these places.

MS has provided a drop-down ImageLocation and added an option “AOT Resource”. Once we select this option, we can specify the resource name that needs to be used.

Check this out

image

 

image

Nice little change MS.

 
Leave a comment

Posted by on February 10, 2012 in AX 2012

 

Tags: , , , ,

Replacing Financial Dimension in Ledger Dimension–Version 2 [AX 2012]

Friends, I had posted one article on replacing financial dimensions within a ledger dimension sometime back. The job there was big and endless. I did some more research and was able to condense it a bit.

Here is the modified job:

static void replaceLedgerDimensions1(Args _args)

{

    #LedgerSHA1Hash

    DimensionSHA1Hash               hash; //To store the calculated hash for DimensionAttributeValueSet

    HashKey                         valueKeyHashArray[]; //To store the has key of dimension in question

    Map                             dimAttrIdx, dimAttrRecId; //to store the dimension index and backing entity type

    DimensionAttributeSetItem       dimAttrSetItem; // Contains the number of dimensions active for a account structure ledger   

    DimensionAttribute              dimAttr; // Contains the financial dimensions records

    DimAttributeHcmWorker           dimAttrWorker; //Backing entity view for Employee type dimension

    DimensionAttributeValue         dimAttrValue; // Contains used financial dimension values

    DimensionAttributeValueSet      dimAttrValueSet; //Contains default dimension records

    DimensionAttributeValueSetItem  dimAttrValueSetItem; //Contains individual records for default dimensions

    LedgerDimensionAccount          sourceDimension = 5637145829, targetDimension; //Record Id DimensionAttributeValueCombination table in which attribute value is to be replaced

    DimensionDefault                sourceDefDimension, targetDefDimension; //To hold the default dimension combination from a Ledger dimension

    LedgerDimensionDefaultAccount   defaultLedgerAccount;

    DimensionEnumeration            dimensionSetId; //Record id for table that contains active dimensions for current ledger

   

    int     dimAttrCount, i;

    int     emplBackEntityType; //Stores the backing entity type for Employee type dimension

    ;

   

    //The employee backing entity will be the view DimAttributeHcmWorker

    emplBackEntityType = tableNum(DimAttributeHcmWorker);

   

    //Initialize the map to store the backing entity types

    dimAttrIdx = new Map(Types::Integer, Types::Integer);

    dimAttrRecId = new Map(Types::Integer, Types::Int64);

 

    //Get the record Id (dimension set id) for current ledger to find active dimensions

    dimensionSetId = DimensionCache::getDimensionAttributeSetForLedger();

 

    //Find all the active dimensions for current ledger except main account and store there

    //backing entity type in the map

    while select * from dimAttr

            order by Name

            where dimAttr.Type != DimensionAttributeType::MainAccount

        join RecId from dimAttrSetItem

            where dimAttrSetItem.DimensionAttribute == dimAttr.RecId &&

                dimAttrSetItem.DimensionAttributeSet == dimensionSetId

    {

        dimAttrCount++;

        dimAttrIdx.insert(dimAttr.BackingEntityType, dimAttrCount);

    }

 

    //initialize hash key array to null

    for (i = 1; i<= dimAttrCount; i++)

    {

        valueKeyHashArray[i] = emptyGuid();

    }

   

    // Get the default dimensions from Ledger dimensions

    sourceDefDimension      = DimensionStorage::getDefaultDimensionFromLedgerDimension(sourceDimension);

   

    //Get the default account from Ledger dimensions

    defaultLedgerAccount    = DimensionStorage::getLedgerDefaultAccountFromLedgerDim(sourceDimension);

   

    //Find the Dimension attribute record for the dimension to work on, in our case it is HcmWorker

    dimAttr.clear();

    select firstOnly dimAttr

        where dimAttr.BackingEntityType == emplBackEntityType

           && dimAttr.Type  != DimensionAttributeType::DynamicAccount;

 

    //Get the backing entity type for the dimension value to process

    select firstOnly dimAttrWorker

        where dimAttrWorker.Value == "51011";

   

    //Find the required Dimension Attribute Value record

    //Create if necessary

    dimAttrValue = DimensionAttributeValue::findByDimensionAttributeAndEntityInst(dimAttr.RecId, dimAttrWorker.RecId, false, true);

   

    //Store the required combination hash keys

    valueKeyHashArray[dimAttrIdx.lookup(emplBackEntityType)] = dimAttrValue.HashKey;

 

    //Calculate the hash for the current values

    hash = DimensionAttributeValueSetStorage::getHashFromArray(valueKeyHashArray, dimAttrCount);

 

    //Null hash indicates no values exist, which may occur if the user entered an invalid value for one dimension attribute

    if (hash == conNull())

    {

        throw error("Wrong value for Employee Dimension");

    }

 

    // Search for existing value set

    dimAttrValueSet = DimensionAttributeValueSet::findByHash(hash);

 

    // This value set does not exist, so it must be persisted

    if (!dimAttrValueSet)

    {

        ttsbegin;

 

        // Insert the value set with appropriate hash

        dimAttrValueSet.Hash = hash;

        dimAttrValueSet.insert();

 

        //Insert Employee dimension set item

        dimAttrValueSetItem.clear();

        dimAttrValueSetItem.DimensionAttributeValueSet = dimAttrValueSet.RecId;

        dimAttrValueSetItem.DimensionAttributeValue = dimAttrValue.RecId;

        dimAttrValueSetItem.DisplayValue = dimAttrWorker.Value;

        dimAttrValueSetItem.insert();

 

        ttscommit;

    }

   

    //Replace the value in default dimension

    targetDefDimension = DimensionDefaultingService::serviceReplaceAttributeValue(sourceDefDimension, dimAttrValueSet.RecId, dimAttr.RecId);

   

    //Combine the target default dimension, default ledger account to get the resultant ledger dimension

    targetDimension = DimensionDefaultingService::serviceCreateLedgerDimension(defaultLedgerAccount, targetDefDimension);

   

    info(strFmt("Before: %1", DimensionAttributeValueCombination::find(sourceDimension).DisplayValue));

    info(strFmt("Before: %1", DimensionAttributeValueCombination::find(targetDimension).DisplayValue));

}

 

image

 
Leave a comment

Posted by on January 30, 2012 in AX 2012

 

Tags: , , ,

Replacing Financial Dimension in Ledger Dimension

Replacing a financial dimension in a Ledger dimension is not straight forward as the replacing of a dimension in Default dimensions. For default dimensions, we had a method serviceReplaceAttributeValue to replace one particular dimension. But for a ledger dimension, we need to do the following:

  1. Get the target ledger dimension
  2. Break it into its component parts (Main account and active dimensions)
  3. Prepare the hash key array for each of them except main account (for only financial dimensions)
  4. In this hash key array replace the hash key of the required financial dimension with the hash key of attribute value to be replaced
  5. Find or create the DimensionAttributeValueSet table
  6. Then use the “serviceCreateLedgerDimension” method of DimensionDefaultingService to get the new ledger dimension and use it

If anybody finds a better solution, please share.

Here is the job that does the steps explained above:

static void replaceLedgerDimensions(Args _args)

{

    #LedgerSHA1Hash

    DimensionSHA1Hash               hash; //To store the calculated hash for DimensionAttributeValueSet

    HashKey                         valueKeyHashArray[]; //To store the has key of dimension in question

    Map                             dimAttrIdx, dimAttrRecId; //to store the dimension index and backing entity type

    DimensionAttributeSetItem       dimAttrSetItem; // Contains the number of dimensions active for a account structure ledger

    DimensionAttribute              dimAttr; // Contains the financial dimensions records

    DimensionAttributeValue         dimAttrValue; // Contains used financial dimension values

    DimensionAttributeValueSet      dimAttrValueSet; //Contains default dimension records

    DimensionAttributeValueSetItem  dimAttrValueSetItem; //Contains individual records for default dimensions

    DimAttributeHcmWorker           dimAttrWorker; //Backing entity view for Employee type dimension

    DimensionEnumeration            dimensionSetId; //Record id for table that contains active dimensions for current ledger

    LedgerDimensionAccount          targetDimension = 5637145829; //Record Id DimensionAttributeValueCombination table in which attribute value is to be replaced

    LedgerDimensionAccount          ledgerDimension; // To hold the resultant DimensionAttributeValueCombination record id

    LedgerDimensionAccount          mainAccDimension; // Record id for LedgerDimension(DimensionAttributeValueCombination) containing default account for main account RecId

    DimensionStorage                dimensionStorage; // Class Dimension storage is used to store and manipulate the values of combination

    DimensionStorageSegment         segment; // Class DimensionStorageSegment will get specfic segments based on hierarchies

 

    int     segmentCount, segmentIndex;

    int     hierarchyCount, hierarchyIndex;

    SysDim  segmentValue, mainAccountValue;

    int     dimAttrCount, i;

    int     emplBackEntityType; //Stores the backing entity type for Employee type dimension

    str     valueStrArray[]; //To store the dimension attribute values

    int64   valueKeyArray[]; //To store the record ids of DimensionAtrributeValue table

    int     backingEntityInstance;

    ;

 

    //The employee backing entity will be the view DimAttributeHcmWorker

    emplBackEntityType = tableNum(DimAttributeHcmWorker);

 

    //Initialize the map to store the backing entity types

    dimAttrIdx = new Map(Types::Integer, Types::Integer);

    dimAttrRecId = new Map(Types::Integer, Types::Int64);

 

    //Get the record Id (dimension set id) for current ledger to find active dimensions

    dimensionSetId = DimensionCache::getDimensionAttributeSetForLedger();

 

    //Find all the active dimensions for current ledger except main account and store there

    //backing entity type in the map

    while select * from dimAttr

            order by Name

            where dimAttr.Type != DimensionAttributeType::MainAccount

        join RecId from dimAttrSetItem

            where dimAttrSetItem.DimensionAttribute == dimAttr.RecId &&

                dimAttrSetItem.DimensionAttributeSet == dimensionSetId

    {

        dimAttrCount++;

        dimAttrIdx.insert(dimAttr.BackingEntityType, dimAttrCount);

        dimAttrRecId.insert(dimAttr.BackingEntityType, dimAttr.RecId);

    }

 

    //initialize hash key array to null

    for (i = 1; i<= dimAttrCount; i++)

    {

        valueKeyHashArray[i] = emptyGuid();

        valueStrArray[i] = ;

        valueKeyArray[i] = 0;

    }

 

    // Default hash key array with required dimension value

    // Get dimension storage

    dimensionStorage = DimensionStorage::findById(targetDimension);

    if (dimensionStorage == null)

    {

        throw error("@SYS83964");

    }

 

    // Get hierarchy count

    hierarchyCount = dimensionStorage.hierarchyCount();

    //Loop through hierarchies to get individual segments

    for(hierarchyIndex = 1; hierarchyIndex <= hierarchyCount; hierarchyIndex++)

    {

        //Get segment count for hierarchy

        segmentCount = dimensionStorage.segmentCountForHierarchy(hierarchyIndex);

 

        //Loop through segments and display required values

        for (segmentIndex = 1; segmentIndex <= segmentCount; segmentIndex++)

        {

            // Get segment

            segment = dimensionStorage.getSegmentForHierarchy(hierarchyIndex, segmentIndex);

 

            // Get the segment information

            if (segment.parmDimensionAttributeValueId() != 0)

            {

                //Get the backing entity type;

                backingEntityInstance = DimensionAttribute::find(DimensionAttributeValue::find(segment.parmDimensionAttributeValueId()).DimensionAttribute).BackingEntityType;

 

                if (backingEntityInstance == tableNum(DimAttributeMainAccount))

                    mainAccountValue = segment.parmDisplayValue();

 

                //Default the required arrays

                if (dimAttrIdx.exists(backingEntityInstance))

                {

                    i = dimAttrIdx.lookup(backingEntityInstance);

                    valueKeyHashArray[i]    = segment.parmHashKey();

                    valueKeyArray[i]        = segment.parmDimensionAttributeValueId();

                    valueStrArray[i]        = segment.parmDisplayValue();

                }

            }

        }

    }

 

    //Find the Dimension attribute record for the dimension to work on, in our case it is HcmWorker

    dimAttr.clear();

    dimAttr = DimensionAttribute::find(dimAttrRecId.lookup(emplBackEntityType));

 

    //Get the backing entity type for the dimension value to process

    select firstOnly dimAttrWorker

        where dimAttrWorker.Value == "51011";

 

    //Find the required Dimension Attribute Value record

    //Create if necessary

    dimAttrValue = DimensionAttributeValue::findByDimensionAttributeAndEntityInst(dimAttr.RecId, dimAttrWorker.RecId, false, true);

 

    //Replace the required combination hash keys and other value arrays

    i = dimAttrIdx.lookup(emplBackEntityType);

    valueKeyHashArray[i]    = dimAttrValue.HashKey;

    valueStrArray[i]        = dimAttrWorker.Value;

    valueKeyArray[i]        = dimAttrValue.RecId;

 

    //Calculate the hash for the current values

    hash = DimensionAttributeValueSetStorage::getHashFromArray(valueKeyHashArray, dimAttrCount);

 

    //Null hash indicates no values exist, which may occur if the user entered an invalid value for one dimension attribute

    if (hash == conNull())

    {

        throw error("Wrong value for Employee Dimension");

    }

 

    // Search for existing value set

    dimAttrValueSet = DimensionAttributeValueSet::findByHash(hash);

 

    // This value set does not exist, so it must be persisted

    if (!dimAttrValueSet)

    {

        ttsbegin;

 

        // Insert the value set with appropriate hash

        dimAttrValueSet.Hash = hash;

        dimAttrValueSet.insert();

 

        // Insert only specified set items use this

        for (i = 1; i <= dimAttrCount; i++)

        {

            if (valueKeyArray[i] != 0)

            {

                dimAttrValueSetItem.clear();

                dimAttrValueSetItem.DimensionAttributeValueSet = dimAttrValueSet.RecId;

                dimAttrValueSetItem.DimensionAttributeValue = valueKeyArray[i];

                dimAttrValueSetItem.DisplayValue = valueStrArray[i];

                dimAttrValueSetItem.insert();

            }

        }

 

        ttscommit;

    }

 

    // Get the default account for main account

    mainAccDimension = DimensionStorage::getDefaultAccountForMainAccountNum(mainAccountValue);

 

    //Find or create the LedgerDimension record for required combination

    ledgerDimension = DimensionDefaultingService::serviceCreateLedgerDimension(

                                                            mainAccDimension,

                                                            dimAttrValueSet.RecId);

 

    info(strFmt("Original %1: %2", targetDimension, DimensionAttributeValueCombination::find(targetDimension).DisplayValue));

    info(strFmt("Replaced %1: %2", ledgerDimension, DimensionAttributeValueCombination::find(ledgerDimension).DisplayValue));

 

}

 

Here is the output:

image

 
7 Comments

Posted by on January 19, 2012 in AX 2012

 

Tags: , , ,

Replace a Financial Dimension in Default Dimensions [AX 2012]

In my earlier post, I had explained how we can set financial dimensions. In this post, I will provide a job by which we can replace one attribute value in a combination of financial dimensions.

The class that we can use is the DimensionDefaultingService and method to use is “serviceReplaceAttributeValue”.

For this purpose, we will use the following combination taken from a customer record.

Fin1

In this financial dimensions, we will replace value if worker from “114” to “51011”.

The job below will be helpful for you to see how this can be achieved.

static void replaceDefaultDimensions(Args _args)

{

    CustTable                       custTable = CustTable::find(‘CUS-00004′); //Customer Record containing Financial Dimension

    DimensionSHA1Hash               hash; //To store the calculated hash for DimensionAttributeValueSet

    DimensionAttribute              dimAttr; // Contains the financial dimensions records

    DimAttributeHcmWorker           dimAttrWorker; //Backing entity view for Employee type dimension

    DimensionDefault                defaultDimension;

    DimensionEnumeration            dimensionSetId; //Record id for table that contains active dimensions for current ledger

    DimensionAttributeValue         dimAttrValue; // Contains used financial dimension values

    DimensionAttributeValueSet      dimAttrValueSet; //Contains default dimension records

    DimensionAttributeValueSetItem  dimAttrValueSetItem; //Contains individual records for default dimensions

    DimensionAttributeSetItem       dimAttrSetItem; // Contains the number of dimensions active for a account structure ledger

 

    HashKey valueKeyHashArray[]; //To store the has key of dimension in question

    Map     dimAttrIdx, dimAttrRecId; //to store the dimension index and backing entity type

    int     dimAttrCount, i;

    int     emplBackEntityType; //Stores the backing entity type for Employee type dimension

 

    //The employee backing entity will be the view DimAttributeHcmWorker

    emplBackEntityType = tableNum(DimAttributeHcmWorker);

 

    //Initialize the map to store the backing entity types

    dimAttrIdx = new Map(Types::Integer, Types::Integer);

    dimAttrRecId = new Map(Types::Integer, Types::Int64);

    //Get the record Id (dimension set id) for current ledger to find active dimensions

    dimensionSetId = DimensionCache::getDimensionAttributeSetForLedger();

 

    //Find all the active dimensions for current ledger except main account and store there

    //backing entity type in the map

    while select * from dimAttr

            order by Name

            where dimAttr.Type != DimensionAttributeType::MainAccount

        join RecId from dimAttrSetItem

            where dimAttrSetItem.DimensionAttribute == dimAttr.RecId &&

                dimAttrSetItem.DimensionAttributeSet == dimensionSetId

    {

        dimAttrCount++;

        dimAttrIdx.insert(dimAttr.BackingEntityType, dimAttrCount);

        dimAttrRecId.insert(dimAttr.BackingEntityType, dimAttr.RecId);

    }

 

    //Get the backing entity type for the dimension value to process

    select firstOnly dimAttrWorker

        where dimAttrWorker.Value == "51011";

 

    //initialize hash key array to null

    for (i = 1; i<= dimAttrCount; i++)

        valueKeyHashArray[i] = emptyGuid();

 

    //Find the Dimension attribute record for the dimension to work on, in our case it is HcmWorker

    dimAttr.clear();

    dimAttr = DimensionAttribute::find(dimAttrRecId.lookup(emplBackEntityType));

 

    //Get the backing entity type for the dimension value to process

    select firstOnly dimAttrWorker

        where dimAttrWorker.Value == "51011";

 

    //Find the required Dimension Attribute Value record

    //Create if necessary

    dimAttrValue = DimensionAttributeValue::findByDimensionAttributeAndEntityInst(dimAttr.RecId, dimAttrWorker.RecId, false, true);

 

    //Replace the required combination hash keys and other value arrays

    i = dimAttrIdx.lookup(emplBackEntityType);

    valueKeyHashArray[i]    = dimAttrValue.HashKey;

 

    //Calculate the hash for the current values

    hash = DimensionAttributeValueSetStorage::getHashFromArray(valueKeyHashArray, dimAttrCount);

 

    //Null hash indicates no values exist, which may occur if the user entered an invalid value for one dimension attribute

    if (hash == conNull())

    {

        throw error("Wrong value for Employee Dimension");

    }

 

    // Search for existing value set

    dimAttrValueSet = DimensionAttributeValueSet::findByHash(hash);

 

    // This value set does not exist, so it must be persisted

    if (!dimAttrValueSet)

    {

        ttsbegin;

 

        // Insert the value set with appropriate hash

        dimAttrValueSet.Hash = hash;

        dimAttrValueSet.insert();

 

        // Insert only specified set items use this

        dimAttrValueSetItem.clear();

        dimAttrValueSetItem.DimensionAttributeValueSet = dimAttrValueSet.RecId;

        dimAttrValueSetItem.DimensionAttributeValue = dimAttrValue.RecId;

        dimAttrValueSetItem.DisplayValue = dimAttrWorker.Value;

        dimAttrValueSetItem.insert();

 

        ttscommit;

    }

 

    defaultDimension = DimensionDefaultingService::serviceReplaceAttributeValue(custTable.DefaultDimension, dimAttrValueSet.RecId, dimAttr.RecId);

 

    ttsBegin;

    custTable.selectForUpdate(true);

    custTable.DefaultDimension = defaultDimension;

    custTable.doUpdate();

    ttsCommit;

}

 

This is the output after running this job.

Fin2

 
3 Comments

Posted by on January 18, 2012 in AX 2012

 

Tags: , , , ,

Defaulting Ledger Dimensions [AX 2012]

In my earlier post, I had described a way to default financial dimensions through code. In this post, I will describe about the way we can default Ledger Dimensions (DimensionAttributeValueCombination) through code.

We have seen how we can fetch the values from a dimension combination in my post here. But what if we have to default them using code.

Say you are creating a general journal and want to default the Account and Offset account fields. These fields have been changed to segmented controls and now store RecIds for DimensionAttributeValueCombination table.

The job below will help you in doing that.

Below are the screen shots of dimensions for the two record ids used below:

image

image

static void setLedgerDimensions(Args _args)

{

    LedgerDimensionAccount  ledgerDimension; // Record id for LedgerDimension(DimensionAttributeValueCombination) containing combination of dimensions

    LedgerDimensionAccount  mainAccDimension; // Record id for LedgerDimension(DimensionAttributeValueCombination) containing default account for main account RecId

   

    RefRecId    emplDimAttrRecId = 5637147951; // For ex. purpose defaulting it to required DimensionAttributeValueSet RecordId

    RefRecId    dimensionRecId = 5637145941; // For ex. purpose defaulting it to required DimensionAttributeValueSet RecordId

    ;

    /*

     * For information on finding the record ids for required dimension combinations

     * Go through the following blog

     * http://sumitsaxfactor.wordpress.com/2011/12/28/defaulting-financial-dimensions-ax-2012/

     */

   

    // Get the default account for main account 110154

    mainAccDimension = DimensionStorage::getDefaultAccountForMainAccountNum("110154");

   

    //Find or create the LedgerDimension record for required combination

    //Param1 – Ledger Dimension record id, in our case Default account for main account

    //Param2 – Default Dimension Record Id for 1st Dimension Combination

    //Param3 – Default Dimension Record Id for 2nd Dimension Combination

    //Param4 – Default Dimension Record Id for 3rd Dimension Combination

    ledgerDimension = DimensionDefaultingService::serviceCreateLedgerDimension(

                                                            mainAccDimension,

                                                            dimensionRecId,

                                                            emplDimAttrRecId);

 

    info(strFmt("%1: %2", ledgerDimension, DimensionAttributeValueCombination::find(ledgerDimension).DisplayValue));

}

This is the output

image

 

Friends I am updating the post to illustrate how we can default dimensions in case the account is  not a ledger account.

In the job above, you can use  the method getDynamicAccount instead of getDefaultAccountForMainAccount and get non-ledger account ledger dimensions. Here is a small job that shows the same.

static void getNonLedgerAccounts(Args _args)

{

    LedgerDimensionAccount  ledgerDim;

    ledgerDim = DimensionStorage::getDynamicAccount(‘VEN-00273′, LedgerJournalACType::Vend);

    info(strFmt("%1 -%2", ledgerDim, DimensionAttributeValueCombination::find(ledgerDim).DisplayValue));

}

 

 
10 Comments

Posted by on December 28, 2011 in AX 2012

 

Defaulting Financial Dimensions [AX 2012]

Next in the series of posts on Ledger dimensions and Financial dimensions is defaulting or setting the financial dimensions for any record. Suppose you have a requirement wherein you need to create a customer via code and default specific dimension (say Employee) to this record.

In AX 2012 dimensions are not directly attached but the combination Record Id is stored. The name generally is DefaultDimension.

This field points to a record in DimensionAttributeValueSet table. This table holds the combination of financial dimensions that a particular record is attached to. The combination is stored in DimensionAttributeValueSetItem table.

The job below will help you in defaulting a dimension: I have put in enough comments to make the job self explanatory. This job will help you find / create a dimension combination record and get the record id to set.

static void setDefaultFinancialDimension(Args _args)

{

    #LedgerSHA1Hash

    DimensionSHA1Hash               hash; //To store the calculated hash for DimensionAttributeValueSet

    HashKey                         valueKeyHashArray[]; //To store the has key of dimension in question

    Map                             dimAttrIdx; //to store the dimension index and backing entity type

    DimensionAttributeSetItem       dimAttrSetItem; // Contains the number of dimensions active for a account structure ledger

    DimensionAttribute              dimAttr; // Contains the financial dimensions records

    DimensionAttributeValue         dimAttrValue; // Contains used financial dimension values

    DimensionAttributeValueSet      dimAttrValueSet; //Contains default dimension records

    DimensionAttributeValueSetItem  dimAttrValueSetItem; //Contains individual records for default dimensions

    DimAttributeHcmWorker           dimAttrWorker; //Backing entity view for Employee type dimension

    DimensionEnumeration            dimensionSetId; //Record id for table that contains active dimensions for current ledger

 

    int dimAttrCount, i;

    int emplBackEntityType; //Stores the backing entity type for Employee type dimension

 

    ;

 

    //The employee backing entity will be the view DimAttributeHcmWorker

    emplBackEntityType = tableNum(DimAttributeHcmWorker);

 

    //Initialize the map to store the backing entity types

    dimAttrIdx = new Map(Types::Integer, Types::Integer);

 

    //Get the record Id (dimension set id) for current ledger to find active dimensions

    dimensionSetId = DimensionCache::getDimensionAttributeSetForLedger();

 

    //Find all the active dimensions for current ledger except main account and store there

    //backing entity type in the map

    while select * from dimAttr

        order by Name

            where dimAttr.Type != DimensionAttributeType::MainAccount

        join RecId from dimAttrSetItem

            where dimAttrSetItem.DimensionAttribute == dimAttr.RecId &&

                dimAttrSetItem.DimensionAttributeSet == dimensionSetId

    {

        dimAttrCount++;

        dimAttrIdx.insert(dimAttr.BackingEntityType, dimAttrCount);

    }

 

    //initialize hash key array to null

    for (i = 1; i<= dimAttrCount; i++)

        valueKeyHashArray[i] = emptyGuid();

 

    //Find the Dimension attribute record for the dimension to work on

    dimAttr.clear();

    select firstonly dimAttr

        where dimAttr.BackingEntityType == emplBackEntityType;

 

    //Get the backing entity type for the dimension value to process

    select firstOnly dimAttrWorker

        where dimAttrWorker.Value == ’000038′;

 

    //Find the required Dimension Attribute Value record

    //Create if necessary

    dimAttrValue = DimensionAttributeValue::findByDimensionAttributeAndEntityInst(dimAttr.RecId, dimAttrWorker.RecId, false, true);

 

    //Store the required combination hash keys

    valueKeyHashArray[dimAttrIdx.lookup(emplBackEntityType)] = dimAttrValue.HashKey;

 

    //Calculate the hash for the current values

    hash = DimensionAttributeValueSetStorage::getHashFromArray(valueKeyHashArray, dimAttrCount);

 

    //Null hash indicates no values exist, which may occur if the user entered an invalid value for one dimension attribute

    if (hash == conNull())

    {

        throw error("Wrong value for Employee Dimension");

    }

 

    // Search for existing value set

    dimAttrValueSet = DimensionAttributeValueSet::findByHash(hash);

 

    // This value set does not exist, so it must be persisted

    if (!dimAttrValueSet)

    {

        ttsbegin;

 

        // Insert the value set with appropriate hash

        dimAttrValueSet.Hash = hash;

        dimAttrValueSet.insert();

 

        /*

         * This Piece of code is only meant for better understanding hence commented

         * Use this code in case you have to handle more than one dimension

         * For our example we have only employee type dimension hence we will not use this for loop

         * Value key array would be the array of different dimension values

         */

        // Insert only specified set items use this

        /*for (i = 1; i <= dimAttrCount; i++)

        {

            if (valueKeyArray[i] != 0)

            {

                dimAttrValueSetItem.clear();

                dimAttrValueSetItem.DimensionAttributeValueSet = valueSet.RecId;

                dimAttrValueSetItem.DimensionAttributeValue = valueKeyArray[i];

                dimAttrValueSetItem.DisplayValue = valueStrArray[i];

                dimAttrValueSetItem.insert();

            }

        }*/

        //Insert Employee dimension set item

        dimAttrValueSetItem.clear();

        dimAttrValueSetItem.DimensionAttributeValueSet = dimAttrValueSet.RecId;

        dimAttrValueSetItem.DimensionAttributeValue = dimAttrValue.RecId;

        dimAttrValueSetItem.DisplayValue = dimAttrWorker.Value;

        dimAttrValueSetItem.insert();

 

        ttscommit;

    }

    info(strFmt("%1", dimAttrValueSet.RecId));

}

 

 
3 Comments

Posted by on December 28, 2011 in AX 2012

 

Getting Individual Dimension Combination Values–Dimension Storage class [AX 2012]

In this post, I will be explaining the method to get individual values for each dimension combination that is created and stored.

Dimension combinations are stored are DimensionAttributeValueCombination class. But they are stored as a combination ex: (100010-AX-00001- – - -). How would you know the value in each combination belongs to what dimension?

The answer is through dimension storage class. This class is used to manipulate these combinations.

The job below helps you in finding out the required values. The job has lots of self explanatory comments.

static void getDimensionCombinationValues(Args _args)

{

    // DimensionAttributeValueCombination stores the combinations of dimension values

    // Any tables that uses dimension  combinations for main account and dimensions

    // Has a reference to this table’s recid

    DimensionAttributeValueCombination  dimAttrValueComb;

    //GeneralJournalAccountEntry is one such tables that refrences DimensionAttributeValueCombination

    GeneralJournalAccountEntry          gjAccEntry;

    // Class Dimension storage is used to store and manipulate the values of combination

    DimensionStorage        dimensionStorage;

    // Class DimensionStorageSegment will get specfic segments based on hierarchies

    DimensionStorageSegment segment;

    int                     segmentCount, segmentIndex;

    int                     hierarchyCount, hierarchyIndex;

    str                     segmentName, segmentDescription;

    SysDim                  segmentValue;

    ;

 

    //Get one record for demo purpose

    gjAccEntry = GeneralJournalAccountEntry::find(5637765403);

 

    setPrefix("Dimension values fetching");

    //Fetch the Value combination record

    dimAttrValueComb = DimensionAttributeValueCombination::find(gjAccEntry.LedgerDimension);

    setPrefix("Breakup for " + dimAttrValueComb.DisplayValue);

 

    // Get dimension storage

    dimensionStorage = DimensionStorage::findById(gjAccEntry.LedgerDimension);

    if (dimensionStorage == null)

    {

        throw error("@SYS83964");

    }

 

    // Get hierarchy count

    hierarchyCount = dimensionStorage.hierarchyCount();

    //Loop through hierarchies to get individual segments

    for(hierarchyIndex = 1; hierarchyIndex <= hierarchyCount; hierarchyIndex++)

    {

        setPrefix(strFmt("Hierarchy: %1", DimensionHierarchy::find(dimensionStorage.getHierarchyId(hierarchyIndex)).Name));

        //Get segment count for hierarchy

        segmentCount = dimensionStorage.segmentCountForHierarchy(hierarchyIndex);

 

        //Loop through segments and display required values

        for (segmentIndex = 1; segmentIndex <= segmentCount; segmentIndex++)

        {

            // Get segment

            segment = dimensionStorage.getSegmentForHierarchy(hierarchyIndex, segmentIndex);

 

            // Get the segment information

            if (segment.parmDimensionAttributeValueId() != 0)

            {

                // Get segment name

                segmentName = DimensionAttribute::find(DimensionAttributeValue::find(segment.parmDimensionAttributeValueId()).DimensionAttribute).Name;

                //Get segment value (id of the dimension)

                segmentValue        = segment.parmDisplayValue();

                //Get segment value name (Description for dimension)

                segmentDescription  = segment.getName();

                info(strFmt("%1: %2, %3", segmentName, segmentValue, segmentDescription));

            }

        }

    }

}

Here is a sample output after running the code:

image

Note: Hiearchies: CEEBD_Dept-CostCenter-Purpose and CorpShared_Dept-CostCenter-Purpose are child hierarchies of “Account structure”.

 
6 Comments

Posted by on December 16, 2011 in AX 2012

 

Dimension Provider Class and Run-time dimension ranges [AX 2012]

While working on a requirement for ledger amounts, I had to find out a way to filter the transactions for a specific dimension value of a specific dimension type; from ledger transactions of a main account.

Now had it been Ax 2009, it was pretty simple where you could provide a range on Dimensions[arrayIndex] field. But in Ax 2012 the dimensions on a transaction are always stored a combination value rather than a separate value.

While running the query, I found a support provided by MS where-in all the dimensions will be added as fields for a table having Ledger dimensions on run-time. Now if we were running a query manually, we will be able to specify the range manually as shown below:

For demo purpose, I am using GeneralJournalAccountEntry table that holds the amounts for transactions posted to a main account

image

Now try and add a range, when you select the drop-down on the Field column, you will notice new fields added to the drop-down

image

The concept behind is that, these fields are added at run-time and when you add a range to any of these fields, a view (DimensionAttributeLevelValueView) will be dynamically added for each field range record you create, as a child DS for GeneralJournalAccountEntry

image 

This is what the SQL statement looks like at the backend

SELECT * FROM GeneralJournalAccountEntry(GeneralJournalAccountEntry_1) JOIN * FROM DimensionAttributeLevelValueView(DimAttCol_GeneralJournalAccountEntry_1_LedgerDimension_5637145354) ON GeneralJournalAccountEntry.LedgerDimension = DimensionAttributeLevelValueView.ValueCombinationRecId AND ((DimensionAttribute = 5637145354)) AND ((DisplayValue = N’000001′))

Now when we are running queries manually, we can specify such kind of a range, what if we have to do the same thing while running a query at a backend or through a code?

Here comes the DimensionProvider class to our rescue. This class will help us add such ranges as required. Look at the sample job below for some guidance.

static void addDimensionRange(Args _args)

{

    Query                   query = new Query();

    QueryRun                queryRun;

    QueryBuildDataSource    qbds;

    DimensionProvider       dimensionProvider = new DimensionProvider();

    GeneralJournalAccountEntry  accEntry;

    DimensionAttribute      dimAttr;

    Name    dimAttrNameEmpl, dimAttrNameCostCenter;

    int i;

    ;

 

    select firstOnly dimAttr where dimAttr.BackingEntityType == tableNum(DimAttributeHcmWorker);

    dimAttrNameEmpl = dimAttr.Name;

   

    select firstOnly dimAttr where dimAttr.BackingEntityType == tableNum(DimAttributeOMCostCenter);

    dimAttrNameCostCenter = dimAttr.Name;

   

    qbds = query.addDataSource(tableNum(GeneralJournalAccountEntry));

 

    dimensionProvider.addAttributeRangeToQuery(query, qbds.name(), fieldStr(GeneralJournalAccountEntry, LedgerDimension), DimensionComponent::DimensionAttribute, SysQuery::valueNotEmptyString(), dimAttrNameEmpl, true);

    dimensionProvider.addAttributeRangeToQuery(query, qbds.name(), fieldStr(GeneralJournalAccountEntry, LedgerDimension), DimensionComponent::DimensionAttribute, SysQuery::valueNotEmptyString(), dimAttrNameCostCenter, true);

 

    queryRun = new QueryRun(query);

    queryRun.prompt();

   

    while(queryRun.next())

    {

        accEntry = queryRun.get(tableNum(GeneralJournalAccountEntry));

        info(strFmt("%1 <–> %2", DimensionAttributeValueCombination::find(accEntry.LedgerDimension).DisplayValue, accEntry.AccountingCurrencyAmount));

    }

}

 

Here is the sample output log

image

This is how the query will be if you prompt the query

image

 
2 Comments

Posted by on December 16, 2011 in AX 2012

 

Find Active Dimensions for a Legal Entity [Ax2012]

This article focuses on getting the active dimensions for a Legal Entity. In Ax 2009, we could get the number of dimensions by using the enumCnt method on SysDimension enum and get the count. Here it is not that straight forward.

Following job will help you in getting the count and display their names;

static void getActiveFinancialDimensions(Args _args)

{

    DimensionAttributeSetItem   dimAttrSetItem; // Contains the number of dimensions active for a account structure ledger

    DimensionAttribute          dimAttr; // Contains the financial dimensions records

    DimensionEnumeration        dimensionSetId; //Record id for table that contains active dimensions for current ledger

   

    int dimAttrCount;

   

    //Get the record Id (dimension set id) for current ledger to find active dimensions

    dimensionSetId = DimensionCache::getDimensionAttributeSetForLedger();

 

    //Find the count of active dimensions for current ledger except main account

    select count(RecId) from dimAttr

            where dimAttr.Type != DimensionAttributeType::MainAccount

        join RecId from dimAttrSetItem

            where dimAttrSetItem.DimensionAttribute == dimAttr.RecId &&

                dimAttrSetItem.DimensionAttributeSet == dimensionSetId;

   

    info(strFmt("Total active financial dimensions for current legal entity: %1", dimAttr.RecId));

               

    //Find all the active dimensions for current ledger except main account and display them

    while select * from dimAttr

        order by Name

            where dimAttr.Type != DimensionAttributeType::MainAccount

        join RecId from dimAttrSetItem

            where dimAttrSetItem.DimensionAttribute == dimAttr.RecId &&

                dimAttrSetItem.DimensionAttributeSet == dimensionSetId

    {

        info(dimAttr.Name);

    }

}

image

 
5 Comments

Posted by on December 14, 2011 in AX 2012

 
 
Follow

Get every new post delivered to your Inbox.

Join 31 other followers