Programmatically inserting into financial/default dimensions in X++ (D365O/AX7)

  • Programmatically inserting into financial/default dimensions in X++ (D365O/AX7)

    Posted by bparker@czarnowski.com on March 16, 2017 at 4:17 pm
    • Brian Parker

      Member

      March 16, 2017 at 4:17 PM

      Hi everybody. Google has failed me, so I thought I’d just ask somewhere. I am new (a couple of months) to D365O/AX, currently implementing (pre-rollout), learning X++ by trying to (re)write the integrations we have in our old ERP system. We are implementing Dynamics 365 For Operations, aka AX7. I have no experience with AX 2012, and limited experience with object oriented programming in general. So if anything sounds like I don’t know what I’m talking about… I probably don’t, please correct me!

      One integration is a human resources system, and I’m trying to sync changes made there to Workers in D365O. (And the related Person/Party/Employment/etc records, it’s crazy, I’m touching 20-30 tables so far and I’m not done.) There are two pieces of data that are going to be stored in Default Dimensions or Financial Dimensions (not sure if those are synonyms, it seems they are) on the HcmWorker record.

      Although there are a ton of blog posts with sample code about READING data from default dimensions, I have yet to find one that covers WRITING to them. I’ll need to be able to insert and update them. I’ve literally spent a couple of days trying to reverse engineer it or find utility methods, and it seems like I’d have to manually insert into at least four tables, with some hash value columns that I still don’t understand how to populate.

      Are there any resources out there? I can’t believe there isn’t an easier way.

      ——————————
      Brian Parker
      Developer
      Czarnowski
      Pittsburgh PA
      ——————————

    • Matthew Hill

      Member

      March 17, 2017 at 10:46 AM

      Brian,

      I would look here for any information related to D365fo / AX7.

      Dynamics 365 for Operations Help Wiki – The source for help for Dynamics 365 for Operations

      It is important to note that Microsoft is still locking down the platform so make sure you Extend instead of Overlay base objects.  If you are just looking to integrate external systems with AX, I recommend checking out the Recurring Integrations in the Wiki.

      Hope that helps!

      Matt

      ——————————
      Matthew Hill
      Director of Business Solutions
      CSG, a Columbus Company
      Cleveland OH
      ——————————
      ——————————————-

    • David Coombs

      Member

      March 17, 2017 at 9:26 AM

      Hello Brian,

       

                      There is help available.  Try msdn.microsoft.com.  Search for Dynamics 365 and see if you can locate what you are looking for.  In older versions, tablename.insert(), tablename.update(), etc. works.  These are methods for the table to do specific things. 

                     

                      Look for best practices in coding as it will save you from a host of problems and headaches.  (https://msdn.microsoft.com/en-us/library/gg509027.aspx – Best practices for developing with Microsoft Dynamics 365).   Also, if you have a partner, see if they have training or search for training related to D365.

       

                      Be patient.  And good luck.  Keep us updated on how you are doing…

       

      Dave Coombs

      Development Services Manager

      Harman Management Corp.

       

       

      ——Original Message——

      Hi everybody. Google has failed me, so I thought I’d just ask somewhere. I am new (a couple of months) to D365O/AX, currently implementing (pre-rollout), learning X++ by trying to (re)write the integrations we have in our old ERP system. We are implementing Dynamics 365 For Operations, aka AX7. I have no experience with AX 2012, and limited experience with object oriented programming in general. So if anything sounds like I don’t know what I’m talking about… I probably don’t, please correct me!

      One integration is a human resources system, and I’m trying to sync changes made there to Workers in D365O. (And the related Person/Party/Employment/etc records, it’s crazy, I’m touching 20-30 tables so far and I’m not done.) There are two pieces of data that are going to be stored in Default Dimensions or Financial Dimensions (not sure if those are synonyms, it seems they are) on the HcmWorker record.

      Although there are a ton of blog posts with sample code about READING data from default dimensions, I have yet to find one that covers WRITING to them. I’ll need to be able to insert and update them. I’ve literally spent a couple of days trying to reverse engineer it or find utility methods, and it seems like I’d have to manually insert into at least four tables, with some hash value columns that I still don’t understand how to populate.

      Are there any resources out there? I can’t believe there isn’t an easier way.

      ——————————
      Brian Parker
      Developer
      Czarnowski
      Pittsburgh PA
      ——————————

    • Brian Parker

      Member

      March 21, 2017 at 12:45 PM

      THANK YOU!!! to everybody for your help, especially Steeve and Denis for the specific code samples. I’ve been busy with other parts of my job but will be circling back to this in the next day or so. I will try them out to make sure that I communicated what I am trying to do, and that these work as I need them to.

      The way I was trying to do it was WAY worse and involved manually touching several tables. I am sure that I have written some other far less efficient code for this import routine! I have plenty to learn.

      Thanks also for the best practices & wiki links… I was aware of them but hadn’t been able to find what I was looking for there. We have a partner (I pity anybody trying to implement without one) but although they were comfortable reading dimensions, writing them was novel to them.

      Good advice on extending rather than customizing. We’ve been forced to do a couple of things as customizations, but I’m avoiding it as much as possible.

      ——————————
      Brian Parker
      Developer
      Czarnowski
      Pittsburgh PA
      ——————————
      ——————————————-

    • Steeve Gilbert

      Member

      March 17, 2017 at 7:43 AM

      Hi Brian,

      Don’t worry, I’m a long time Ax developer and that also took me a while to find/understand how to update this new Default Dimension.  The first time I work with it was to update InventTable.DefaultDimension so I’ll use that as my example below.  Here’s a static method I’ve build (with help of some blog can’t remember where) to simplify DefaultDimension modification.

      /// <summary>
      /// Modify a default dimension
      /// </summary>
      /// <param name = “defaultDimension”> RecId of an existing DefaultDimension (ex : InventTable.DefaultDimension) so
      /// you can add or remove value to that DefaultDimension defaultDimension can be 0 if you want to start
      /// a DefaultDimension from scratch</param>
      /// <param name = “dimAttr”>RecId from DimensionAttribute.RecId of the attribute you want to change</param>
      /// <param name = “dimValue”>Value to set for that DimensionAttribute</param>
      /// <returns>RecId that you can save in your DefaultDimension field (like InventTable.DefaultDimension)</returns>
      static RecId Write(RecId defaultDimension, RecId dimAttr, str dimValue)
      {

      DimensionAttributeValueSetStorage dimStorage;
      DimensionAttribute dimAttribute;
      DimensionAttributeValue dimAttributeValue;

      //Find or create a storage dimension that will contain each dimension attribute and their value
      //”defaultDimension” is the RecId of an existing DefaultDimension (ex : InventTable.DefaultDimension) so
      // you can add or remove value to that DefaultDimension.  defaultDimension can be 0 if you want to
      // create a DefaultDimension from scratch
      dimStorage = DimensionAttributeValueSetStorage::find(defaultDimension);

      if (dimValue)
      {
      dimAttribute = DimensionAttribute::find(dimAttr);
      dimAttributeValue = DimensionAttributeValue::findByDimensionAttributeAndValue(dimAttribute, dimValue, true, true);
      dimStorage.addItem(dimAttributeValue);
      }
      else
      {
      //If there’s no value, that means we want to remove that Dimension Attribute
      dimStorage.removeDimensionAttribute(dimAttr);
      }

      return dimStorage.save();

      }

      So you can add multiple Dimension Attribute to DefaultDimension by calling this method for each Dimension Attribute and passing the DefaultDimension return from the first call onto the next call.  The final DefaultDimension will contain all your DimensionAttribute.  Or you can create a better method that handle that all for you. šŸ™‚

      As for Financial Dimension, I think you refer to LedgerDimension.  I haven’t played much with that.  The only place i used that was to set a Ledger Account on a record like InventPosting.LedgerDimension.  The code I used was that :
      LedgerDefaultAccountHelper::getDefaultAccountFromMainAccountRecId(MainAccount::findByMainAccountId(mainAcc).RecId)
      It returns the RecId you need to put in LedgerDimension if you want it to refer to the Main Account “mainAcc”. 

      Hope that helps.  Let us know if you have more questions.

      ——————————
      Steeve Gilbert
      Analyst Programmer
      Boa-Franc S.E.N.C.
      QC, Canada
      ——————————
      ——————————————-

    • Brian Parker

      Member

      March 22, 2017 at 6:43 PM

      Turns out Steeve’s was really  close to what I wanted, close enough for me to make the final leap. Presented below is my version with two small changes:

      1. Note in the “summary” about calling it, with sample syntax. You need to follow the call with an update to your table (as far as I could tell) for the change to stick. That threw me for a little while… please correct me if I’m mistaken or could handle it better.
      2. I wanted to be able to just feed the attribute name as a string, instead of looking up a RecID; that’s easier to use (for my purposes, at least).

      /// <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, 'BusinessUnit', '004');
      /// 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)
      {
      DimensionAttributeValueSetStorage dimStorage;
      DimensionAttribute dimAttribute;
      DimensionAttributeValue dimAttributeValue;

      RecId dimAttr;

      // 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 will contain each dimension attribute and their value
      //"defaultDimension" is the RecId of an existing DefaultDimension (ex : InventTable.DefaultDimension) so
      // you can add or remove value to that DefaultDimension. defaultDimension can be 0 if you want to
      // create a DefaultDimension from scratch
      dimStorage = DimensionAttributeValueSetStorage::find(_defaultDimension);

      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();
      }

      ——————————
      Brian Parker
      Developer
      Czarnowski
      Pittsburgh PA
      ——————————
      ——————————————-

    • Brian Parker

      Member

      March 23, 2017 at 11:04 AM

      Hmm. Clearly I could also use tips on formatting code for this forum.

      ——————————
      Brian Parker
      Developer
      Czarnowski
      Pittsburgh PA
      ——————————
      ——————————————-

    • Denis Marcoux

      Member

      March 17, 2017 at 8:05 AM

      Hi Brian,

      Creating a defautltDimension looks something like this.  Parameter _value i a container that passes the dimension values into the method.

      public static DimensionDefault createDefaultDimension(container _value, boolean _createIfNotFound = true)
              #{
              #    DimensionAttributeValueSetStorage   valueSetStorage = new DimensionAttributeValueSetStorage();
              #    DimensionDefault                    result;
              #    int                                 i;
              #    DimensionAttribute                  dimensionAttribute;
              #    DimensionAttributeValue             dimensionAttributeValue;
              #
              #    container               conAttr;
              #    container               conValue = _value;
              #    str                     dimValue;
              #
              #    String255          Dimension1Name = ‘Department’;
              #    String255          Dimension2Name = ‘BusinessUnit’;
              #    String255          Dimension3Name = ‘Project’;
              #
              #    // Créer un container avec les noms de dimension
              #    conAttr = [strFmt(“%1”,Dimension1Name),
              #               strFmt(“%1”,Dimension2Name),
              #               strFmt(“%1”,Dimension3Name)
             
              #              ];
              #
              #    for (i = 1; i <= conLen(conAttr); i++)
              #    {
              #        dimensionAttribute = dimensionAttribute::findByName(conPeek(conAttr,i));
              #
              #        if (dimensionAttribute.RecId == 0)
              #        {
              #            continue;
              #        }
              #
              #        dimValue = conPeek(conValue,i);
              #
              #        if (dimValue != “”)
              #        {
              #            // _createIfNotFound is “true”. A dimensionAttributeValue record will be created if not found.
              #            dimensionAttributeValue =
              #                    dimensionAttributeValue::findByDimensionAttributeAndValue(dimensionAttribute,dimValue,false,_createIfNotFound);
              #
              #            // Add the dimensionAttibuteValue to the default dimension
              #            valueSetStorage.addItem(dimensionAttributeValue);
              #        }
              #    }
              #    result = valueSetStorage.save();
              #    return result;
              #}

      ——————————
      Denis Marcoux
      Developer
      Grics
      Montreal QC
      ——————————
      ——————————————-

    bparker@czarnowski.com replied 8 years, 6 months ago 1 Member · 0 Replies
  • 0 Replies

Sorry, there were no replies found.

The discussion ‘Programmatically inserting into financial/default dimensions in X++ (D365O/AX7)’ is closed to new replies.

Start of Discussion
0 of 0 replies June 2018
Now

Welcome to our new site!

Here you will find a wealth of information created for peopleĀ  that are on a mission to redefine business models with cloud techinologies, AI, automation, low code / no code applications, data, security & more to compete in the Acceleration Economy!