Archive for the ‘Knowledge base (Development)’ Category

What the difference between InventOnHand and InventDimOnHand classes and in what cases they must be used?

Axapta InventOnHand class is wrapper for InventSum table. Unique index for InventSum table is ItemId + InventDimId. In other word, this class is used to get on hand for item with specific dimension. For example, if you require getting on-hand qty for “Bottle” items that have “green” color, “standard” size and are stored in “22” warehouse, “1” Aisle, “4” Shelf then you use InventOnHand class.

But, if you require getting on-hand qty for warehouse location then InventOnHand class couldn’t help us. Because one location could contains different items. Or if you require get on-hand qty for pallet. In these cases InventDimOnHand class must be used. This class is used when you require on-hand qty for specific inventDim. InventDimOnHand сlass consists of InventDimOnHandMember classes. Each InventDimOnHandMember class contains information about Item, Dimensions and Qty.

Example: “Get location on-hand”

static void rmsOnHandQty(Args _args)
{
WMSLocation wmsLocation;
InventDim inventDimLocal;
InventDimParm inventDimParmCriteria;
InventDimOnHand inventDimOnHand;
InventDimOnHandIterator inventDimOnHandIterator;
InventDimOnHandMember inventDimOnHandMember;
Qty qty;
;

select firstonly wmsLocation;

inventDimLocal.InventLocationId = wmsLocation.inventLocationId;
inventDimLocal.wMSLocationId = wmsLocation.wMSLocationId;
inventDimLocal = InventDim::findOrCreate(inventDimLocal);

inventDimParmCriteria.wmsLocationIdFlag = NoYes::Yes;
inventDimParmCriteria.InventLocationIdFlag = NoYes::Yes;

inventDimOnHand = InventDimOnHand::newPhysicalArrived('', inventDimLocal, inventDimParmCriteria, inventDimOnHandLevel::Item, null);
inventDimOnHandIterator = inventDimOnHand.onHandIterator();
while (inventDimOnHandIterator.more())
{
inventDimOnHandMember = inventDimOnHandIterator.value();
qty += inventDimOnHandMember.parmInventQty();
inventDimOnHandIterator.next();
}

info(strfmt("%1 location has %2 items", wmsLocation.wMSLocationId, num2str(qty,2,2,1,1)));
}

Technorati Tags: ,

This article contains descriptions of select statement patterns that can be used in the Microsoft Dynamics AX (Axapta).

The list of select statement patterns provided is as follows:

  1. Enable/Disable condition
  2. Switch condition
  3. Enable/Disable join table with condition

Enable/Disable Condition

Use this pattern when the condition in the “where” clause is dependant of a parameter.
For example, we need to perform some procedure with either all Customer or Customers with invoice account only. It depends on the User input parameter. We create a periodic job with the following dialog box:

Process Customers

Process Customers

We will assume that the Customer with invoice account check box has the dialogField name in the code.

The select statement will have the following view in the “run” method:

while select custTable
where (!dialogField.value() || custTable.InvoiceAccount != '')

If the check box is selected, !dialogField.value() returns false and custTable.InvoiceAccount != ” will be taken into account. If the check box isn’t selected, !dialogField.value() returns true (so there is no sense what return the custTable.InvoiceAccount != ” condition). In other words, if the check box is selected, only Customers with Invoice accounts will be searched. Otherwise, all Customers will be searched.

General structure looks as follows: where (!EnableConditionFlag || condition)

Switch Condition

Use this pattern when either one or another condition dependant of parameter must be applied to the select statement.

For example, we need to perform a procedure with items of either a BOM item or items of other item types. We need to create a periodic job with a dialog box. The dialog box contains only one BOM type checkbox. We will assume that the BOM type check box has the dialogField name in the code.

In the run method, we write the following select statement:

while select inventTable
where ((!dialogField.value() && inventTable.ItemType != ItemType::BOM) ||
       (dialogField.value()  && inventTable.ItemType == ItemType::BOM))

If the BOM type check box is selected, the first parenthesis returns false and everything depends on the second parenthesis where the inventTable.ItemType == ItemType::BOM clause is checked. If the BOM type check box isn’t selected, the second parenthesis returns false and everything depends on the first parenthesis where the inventTable.ItemType != ItemType::BOM clause is checked. In other words, if the check box is selected, the only BOM item will be searched. Otherwise, only not BOM items will be searched.

General structure looks as follows: where ((!Condition2Flag && condition 1) || (Condition2Flag && condition 2))

Enable/Disable Join Table with Condition

Use this pattern when a joined table with a condition can either contain records or be empty.

For example, we need select sales orders without Recipient or terminated Recipient. The SalesTaker field in the SalesTable table stores the Recipient ID. The Status field in the EmplTable table stores the Recipient’s status (None, Employed, or Resigned).

The select statement has the following view:

while select SalesTable
notexists join EmplTable
where EmplTable.EmplId == SalesTable.SalesTaker &&
      EmplTable.status != HRMEmplStatus::Resigned

If EmplTable.status is Resigned or the Sales table record doesn’t have the Recipient, the Sales table record will be selected.

General structure looks as follows: notexists join <TableName> where <relation clause> && (condition != required value)

If you know other interesting patterns, please write them in the comments ;)

Technorati Tags: , ,

static public HWND getActiveWhd()
{
    HWND                  AxClient, AxChild;
    ;

    AxClient = WinApi::findWindowEx(infolog.hWnd(), 0, "MDIClient", "");
    AxChild = WinApi::findWindowEx(AxClient, nullvalue(AxChild), "", ""); 
    return AxChild;
}
void moveToProject(HWND AxChild)
{
    ProjectNode     nodeMenuItemProj;
    ;

    nodeMenuItemProj = CDT_Global::extractProjNode(AxChild);
    if (nodeMenuItemProj)
    {
        nodeMenuItemProj = nodeMenuItemProj.getRunNode();

        nodeMenuItemProj.lockUpdate();
        nodeMenuItemProj.addUtilNode(UtilElementType::Form, formName);
        nodeMenuItemProj.unlockUpdate();

        nodeMenuItemProj.AOTcompile(1);
        nodeMenuItemProj.AOTcompile(1);

        nodeMenuItemProj.AOTSave();
    }
}

Use inRange methods from Global class

static boolean inRange(str _rangeValue, anytype _value)

Example:

{
    str 		_rangeValue;
    str 		_value ;
    boolean 	        result;
    ;
    _rangeValue  = ‘200..500’;
    _value          =  ‘300’;

    result  = Global::inRange (_rangeValue , _value);
}

The result variable will be equal to true


xInfo inf;
;
inf = new xInfo();
if( inf )
{
inf.language();
}






void SummaryProjectLookup(FormControl ctrl)
{
    SysTableLookup sysTableLookup = SysTableLookup::newParameters(tableNum(ProjTable),ctrl);
    Query query = New Query();
    QueryBuildDataSource queryBuildDataSource = query.addDataSource(tableNum(ProjTable));
    QueryBuildRange queryBuildRange;
    ;

    sysTableLookup.addLookupfield(fieldNum(ProjTable, ProjId));
    sysTableLookup.addLookupfield(fieldNum(ProjTable, Name));
    sysTableLookup.addLookupfield(fieldNum(ProjTable, Status));

    queryBuildRange = queryBuildDataSource.addRange(fieldNum(ProjTable, Type));
    queryBuildRange.value(queryValue(ProjType::Summary));
    sysTableLookup.parmQuery(query);
    sysTableLookup.performFormLookup();
}

public void lookup()
{
    element.SummaryProjectLookup(this);
}
edit LabelString helpTextValue( boolean _set, LabelString _value )
{
    LabelString ret;
    Label label;
    xInfo inf;
    ;
    if( _set )
    {
        CDT_MenuItemList.HelpText = _value;
    }
    if( isHelpTextControlActive ) ret = CDT_MenuItemList.HelpText;
    else
    {
        inf = new xInfo();
        if( inf )
        {
            label = new Label( inf.language() );
            if( label ) ret = label.extractString( CDT_MenuItemList.HelpText );
        }
    }

    return ret;
}

Code in form’s outer scope:


TmpTable 	tmpTable;
FormRun        formRun;
;
...
// Fill tmpTable with data here
…
args.record( tmpTable );
formRun = classFactory.formRunClass( args );
formRun.init();
formRun.run();
formRun.detach();
formRun.wait();
if( formRun.closedOk() )
{
	…
// Process data from tmpTable updated in form here
	…
}

Code in form, in the temporary table datasource – TmpTableDS:


public void init()
{
    TmpTable 	tmpTable;
    ;

    tmpTable = element.args().record();

    super();

    TmpTableDS.setTmpData( tmpTable );
}

Searching in AOT groups like Classes, Forms, etc. by scanning tree nodes is unacceptable due to performance reasons. For searching in AOT groups you should scan system table UtilElements. See example in SysAotFind form – class SysUtilScanSource.

Advertorial
Interact and Engage
Follow AxaptaTraining on Twitter
Google Translate