Processing Business Tasks - Building a Display dimensions dialog


People who use the Dynamics AX application often, probably must have already noticed the Display dimensions button on some forms. Normally it is displayed on its own or under the Inventory button. This button always comes on the forms that have an inventory item and its dimensions, for example Sales order or Purchase order forms. Normally, item dimensions are Configuration, Size, Color, Warehouse, and so on depending on the license and system configuration. The button invokes a dialog that allows controlling the number of displayed inventory dimensions in the overview grid.
In this recipe, we will learn how to create such a button and all the associated functionality. This is very useful when creating custom forms with inventory controls.
For this recipe, we will define our requirement to have a default item for each item group. So we are going to add an item number and inventory dimension controls to the Item group form.

How to do it...

  1. 1. Open the InventItemGroup table in AOT and add a new field:
    PropertyValue
    TypeString
    NameItemId
    ExtendedDataTypeItemId

  1. 2. Add another field to the same table:
    PropertyValue
    TypeString
    NameInventDimId
    ExtendedDataTypeInventDimId

  1. 3. In AOT create a new job with the following code:
    static void InventItemGroupPopulateDim(Args _args)
    
    {
    InventItemGroup inventItemGroup;
    InventDimId inventDimIdBlank;
    ;
    inventDimIdBlank =
    InventDim::findOrCreateBlank(false).inventDimId;
    ttsbegin;
    while select forupdate inventItemGroup
    {
    inventItemGroup.InventDimId = inventDimIdBlank;
    inventItemGroup.doUpdate();
    }
    ttscommit;
    }
    
  2. 4. Run the job to populate the empty InventDimId field in the InventItemGroup table:
  3. 5. In AOT, create a new class named InventDimCtrl_Frm_ItemGroup with the following code:
    class InventDimCtrl_Frm_ItemGroup extends InventDimCtrl_Frm
    
    {
    }
    public static InventDimCtrl_Frm_ItemGroup construct()
    
    {
    return new InventDimCtrl_Frm_ItemGroup();
    }
    public static InventDimCtrl_Frm_ItemGroup newFromForm(
    FormRun _formRun)
    
    {
    InventDimAxFormAdapter adapter;
    InventDimCtrl_Frm_ItemGroup inventDimCtrl;
    ;
    adapter = InventDimAxFormAdapter::newFromForm(_formRun);
    inventDimCtrl = InventDimCtrl_Frm_ItemGroup::construct();
    inventDimCtrl.parmCallingElement(adapter);
    inventDimCtrl.init();
    return inventDimCtrl;
    Display dimensions dialogDisplay dimensions dialogcreating, steps}
    NoYes mustEnableField(FieldId _dimFieldId)
    
    {
    boolean ret;
    ;
    ret = this.dimSearch().find(
    inventDimGroupId,
    _dimFieldId);
    ret = ret && this.dimSearch().dimActive();
    return ret;
    }
    NoYes mustMarkFieldAsMandatory(FieldId _dimFieldId)
    
    {
    boolean ret;
    Display dimensions dialogDisplay dimensions dialogcreating, steps;
    ret = this.mustEnableField(_dimFieldId);
    ret = ret && this.dimSearch().dimMandatory();
    return ret;
    }
    
    
           
  4. 6. Open the InventItemGroup form in AOT and add the following line of code to its class declaration:
    InventDimCtrl_Frm_ItemGroup inventDimFormSetup;
    
  5. 7. Create the following methods on the same form:
    void updateDesign(InventDimFormDesignUpdate _update)
    
    {
    InventDimParm inventDimParmVisibleGrid;
    InventTable inventTable;
    ;
    switch (_update)
    {
    case InventDimFormDesignUpdate::Init:
    if (!inventDimFormSetup)
    inventDimFormSetup =
    InventDimCtrl_Frm_ItemGroup::newFromForm(
    element);
    inventDimParmVisibleGrid.ConfigIdFlag = true;
    inventDimParmVisibleGrid.InventSizeIdFlag = true;
    inventDimParmVisibleGrid.InventColorIdFlag = true;
    inventDimFormSetup.parmDimParmVisibleGrid(
    inventDimParmVisibleGrid);
    case InventDimFormDesignUpdate::Active:
    case InventDimFormDesignUpdate::FieldChange:
    inventTable = InventTable::find(
    InventItemGroup.ItemId);
    inventDimFormSetup.formActiveSetup(
    inventTable.DimGroupId);
    inventDimFormSetup.formSetControls(true);
    break;
    default:
    throw error(Error::missingParameter(null));
    }
    }
    public void init()
    
    Display dimensions dialogDisplay dimensions dialogcreating, steps{;
    super();
    element.updateDesign(InventDimFormDesignUpdate::Init);
    }
    Object inventDimSetupObject()
    
    {
    return inventDimFormSetup;
    }
    
    
           
  6. 8. Add a new data source to the form:
    PropertyValue
    NameInventDim
    TableInventDim
    JoinSourceInventItemGroup
    LinkTypeInnerJoin
    DelayActiveNo

  1. 9. Override the active() and validateWrite() methods of the InventItemGroup data source with the following code:
    public int active()
    
    {
    int ret;
    ;
    ret = super();
    element.updateDesign(InventDimFormDesignUpdate::Active);
    return ret;
    }
    public boolean validateWrite()
    
    {
    boolean ret;
    ;
    InventItemGroup.InventDimId =
    InventDim::findOrCreate(InventDim).InventDimId;
    ret = super();
    return ret;
    Display dimensions dialogDisplay dimensions dialogcreating, steps}
    
  2. 10. Override modified() on the ItemId field on the same data source:
    public void modified()
    
    {;
    super();
    element.updateDesign(
    InventDimFormDesignUpdate::FieldChange);
    inventDim.clearNotSelectedDim(
    element.inventDimSetupObject().parmDimParmEnabled());
    }
    
  3. 11. Add a new StringEdit control to the form's grid:
    PropertyValue
    NameInventItemGroup_ItemId
    DataSourceInventItemGroup
    DataFieldItemId

  1. 12. Also add a new Group control to the form's grid:
    PropertyValue
    NameInventoryDimensionsGrid
    DataSourceInventDim
    DataGroupInventoryDimensions
    AutoDataGroupYes

  1. 13. Add a new TabPage control to the form's Tab:
    PropertyValue
    NameDimension
    CaptionDimension

  1. 14. Add a new Group control to the created tab page:
    PropertyValue
    NameInventoryDimensions
    DataSourceInventDim
    DataGroupInventoryDimensions
    AutoDataGroupYes

  1. 15. And finally, add a new MenuItemButton control to the form's ButtonGroup:
    PropertyValue
    NameInventoryDimensions
    DataSourceInventDim
    DataGroupInventoryDimensions
    AutoDataGroupYes

  1. 16. As a result, the form should look like following in AOT:
  1. 17. Now open Inventory management | Setup | Item group and notice the new inventory dimensions controls:
  1. 18. Use the Dimensions display button to control which dimension fields should be visible on the form:

How it works...

In Dynamics AX each unique combination of inventory dimensions (Configuration, Size, Color, Warehouse, etc.) is stored in the InventDim table and has a unique identification number. This prevents us from having redundant information in every table where we need to store inventory dimensions. By using this principle instead of having a number of fields for each dimension separately, we have only one field referring to theInventDim table.
In this demonstration, the first step is to add two new fields to the InventItemGroup table. One field will store inventory item number and the other one, the number of the inventory dimension combination. In order to maintain data integrity of the existing item group, it is also important to populate the InventDimIdfield with the value of empty dimension combination. We create and run a new job namedInventItemGroupPopulateDim, which does exactly that. Such a task is not necessary when creating new tables, which obviously initially do not have any data. The job loops through all item group records and fills the InventDimId field with the value representing the empty dimension combination, which is found by calling findOrCreateBlank() on the InventDim table.
Now when fields and data are ready, we need to create a helper class calledInventDimCtrl_Frm_ItemGroup and design it to correctly handle dimension controls on the Item groupform. This class extends InventDimCtrl_Frm, which contains all the generic functionality. We only need to create new and override several existing member methods in order to implement custom behavior:
  • construct() is used to return a new instance of this class.
  • newFromForm() creates a new instance of this class and additionally ensures correct integration with the form.
  • mustEnableField() is used to determine whether dimension control is enabled. It accepts a dimension field number as an argument. Here we check if a particular dimension is active for the current dimension group, which is assigned to the current item. This method is automatically called every time the item number changes or the user selects a new line to make sure that the correct dimension controls are enabled or disabled.
  • mustMarkFieldAsMandatory() is used to determine whether the dimension control requires mandatory user input. In this method, first we check if the current dimension is enabled and if it is then it is defined as mandatory in settings. The method returns true if both checks are positive.
And finally, we modify the InventItemGroup form. We start with its methods:
  • In its class declaration we declare the InventDimCtrl_Frm_ItemGroup object..
  • A new updateDesign() is called from a number of other places. The method is split into two parts one for initialization and another one for updating form design when something changes. The initialization section uses newFromForm() of the InventDimCtrl_Frm_ItemGroup class to create a new instance, if it is not created yet. Here we can also specify which dimension controls are visible initially by calling parmDimParmVisibleGrid() on the inventDimFormSetup object. In this recipe, we chose to show Configuration, Size, and Color controls by default. The second section updates inventDimFormSetup with a new item dimension group if the user changes an item or selects another line. As we have seen before, the item dimension group is used to determine which dimension controls should be enabled and be mandatory.
  • Form's init() calls updateDesign() to make sure that the inventDimFormSetup object is initialized properly.
  • inventDimSetupObject() is used to get the reference to the inventDimFormSetup instance from theInventory dimensions dialog.
A new data source InventDim has to be added to the form and it will be a source for dimension controls. It is connected to InventItemGroup using an inner join.
We also need to override several InventItemGroup data source methods to make sure everything works correctly:
  • active() calls the form's updateDesign(), which updates dimension controls. active() is called every time the user selects another record.
  • In validateWrite() we use findOrCreate() of the InventDim table to search for an existing inventory dimension combination. This method accepts a InventDim data source as a buffer for retrieving user input values. findOrCreate() creates a new dimension combination and its number if no existing dimension is found.
  • modified() on the ItemId field behaves the same way as active() does, plus it clears non relevant dimension controls once the user selects a new item.
The final step is to add the item and its dimensions to the overview grid. We also add an additional tab page where all dimensions are listed. This ensures that the user has access to the required dimension even if it is hidden on the overview page. And of course, we add a new MenuItemButton button, which calls the InventDimParmFixed menu item upon user selection, to open dimension setup form.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.