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...
-
-
-
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;
}
-
4. Run the job to populate the empty InventDimId field in the InventItemGroup table:
-
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;
}
-
-
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;
}
-
-
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}
-
-
11. Add a new StringEdit control to the form's grid:
Property Value
Name InventItemGroup_ItemId
DataSource InventItemGroup
DataField ItemId
-
12. Also add a new Group control to the form's grid:
Property Value
Name InventoryDimensionsGrid
DataSource InventDim
DataGroup InventoryDimensions
AutoDataGroup Yes
-
13. Add a new TabPage control to the form's Tab:
Property Value
Name Dimension
Caption Dimension
-
-
-
-
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:
-
-
-
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.
-
-
-
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.
-
-
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:
-
-
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.
-
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.
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; }
- 4. Run the job to populate the empty InventDimId field in the InventItemGroup table:
- 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; }
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; }
- 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}
- 11. Add a new StringEdit control to the form's grid:
Property Value Name InventItemGroup_ItemId DataSource InventItemGroup DataField ItemId
- 12. Also add a new Group control to the form's grid:
Property Value Name InventoryDimensionsGrid DataSource InventDim DataGroup InventoryDimensions AutoDataGroup Yes
- 13. Add a new TabPage control to the form's Tab:
Property Value Name Dimension Caption Dimension
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.
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.
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.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.