View Details – Open another form from a button by passing args record

void clicked()
InventJournalTable inventJournalTable;
WMSJournalTable wmsJournalTable;
VendPackingSlipJour vendPackingSlipJour;
InventTransferTable inventTransferTable;
Args args = new Args();

wmsJournalTable = WMSJournalTable::find(Table.JournalId);



NOTE: use element.args().menuItemName() == menuItemDisplayStr(<menu item name>) in if condition to check from which menuitem form is called


Find financial dimension value based on dimension

public static DimensionValue trsGetAgency(LedgerDimensionAccount _ledgerDimension)
DimensionAttributeValueGroupCombination dimAttrValueGroupCombo;
DimensionAttributeLevelValue dimAttrLevelValue;
DimensionAttributeValue dimAttrValue;
DimensionAttribute dimAttr;

select RecId from dimAttrValueGroupCombo
join displayValue from dimAttrLevelValue
join RecId, DimensionAttribute from dimAttrValue
join Name from dimAttr
where dimAttrValue.DimensionAttribute == dimAttr.RecId &&
dimAttr.BackingEntityTableId == tableNum(OMOperatingUnit) &&
dimAttrValueGroupCombo.DimensionAttributeValueCombination == _ledgerDimension &&
dimAttrLevelValue.DimensionAttributeValueGroup == dimAttrValueGroupCombo.DimensionAttributeValueGroup &&
dimAttrValue.RecId == dimAttrLevelValue.DimensionAttributeValue;

return dimAttrLevelValue.DisplayValue;

X++ Performance tips

Tip 1: Measure execution time of your code
Measuring is knowing. Before you start changing code, make sure you have a set of data you can keep reusing for your tests. Measure the performance of your code on that data after each change in code so you know the impact of your changes.

One way to do this is by using the Winapi::getTickCount() (or WinApiServer::getTickCount() if your code runs on server) method.

static void KlForTickCountSample(Args _args)
int ticks;

// get the tickcount before the process starts
ticks = winapi::getTickCount();

// start the process
sleep(2000)// simulate 2 seconds of processing

// compare tickcount
ticks = winapi::getTickCount()  ticks;

// display result
info(strfmt(‘Number of ticks: %1’, ticks));

Tip 2: limit the number of loops
A LOT of time goes into loops. If you have a performance problem, start looking for loops. Code can run really fast, but it can get slow when it is executed too many time, eg, in a loop.

Tip 3: avoid ‘if’ in ‘while select’
When there is a ‘if’ in a ‘while select’, see if you can rewrite it a a where statement in your select. Don’t be affraid use a join either. Consider the following example:

static void KlForIfInLoop(Args _args)
VendTable vendTable;

// usually slower
while select vendTable
if(vendTable.VendGroup == ‘VG1’)

// usually faster
while select vendTable
where vendTable.VendGroup == ‘VG1’

Tip 4: avoid double use of table methods
Using table methods a lot can get really slow if you do it wrong.

Consider the following example:

static void klForTableMethodsSlow(Args _args)
SalesLine salesLine;
InventDim inventDim;

// select a salesline
select firstonly salesLine;

inventDim.InventColorId = salesLine.inventDim().InventColorId;
inventDim.InventSizeId  = salesLine.inventDim().InventSizeId;
inventDim.inventBatchId = salesLine.inventDim().inventBatchId;

This example code looks nice, but there’s a problem.
The salesLine.inventDim() method contains the following:

InventDim inventDim(boolean  _forUpdate = false)
return InventDim::find(this.InventDimId, _forUpdate);

This means that the invendDim record is read three times from the database.
It is better to declare the inventDim record locally and only retrieve it once:

static void klForTableMethodsFast(Args _args)
SalesLine salesLine;
InventDim inventDim;
InventDim inventDimLoc;

// select a salesline
select firstonly salesLine;

inventDimLoc = salesLine.inventDim();

inventDim.InventColorId = inventDimLoc.InventColorId;
inventDim.InventSizeId  = inventDimLoc.InventSizeId;
inventDim.inventBatchId = inventDimLoc.inventBatchId;

Tip 5: Don’t put too much code on tables
Code on tables is usually fast, but things can get slow if you use it to much.
Say you have a table with an InventDimId field. If you have 5 methods that need the InventDim record, because you don’t have a classDeclaration method on your table, you need to call this function 5 times, once in every method:


When you put these methods on a class, you could optimise it by fetching the record only once and storing it in the classDeclaration, or better, passing it as a parameter to your methods.

An other example is fetching parameters from parameter tables, eg InventParameters::find(). On a table, you have to fetch it each time you call a method. In a class, you would probably optimize your code to only fetch the parameter record once.

Tip 6: Use the fastest code
For some tasks, there is ‘special code’ that is faster than the code you would normally write.
For example:

// slower
while select forupdate custTable
where custTable.custGroup == ‘TST’

// faster
delete_from custTable
where custTable.custGroup == ‘TST’;

The same applies to update_recordset for updating records.

Also, when adding values to the end of a container

cont += “a value”;

is faster than

cont = conins(cont, conlen(cont), “a value”);

Tip 6: Every optimization counts
Remember that every optimization you do to you code counts, even if it’s a little one. Small performance tweaks can have a huge effect once you process large quantities of data. So don’t be lazy, and optimize :-).

Cost price of an item in ax 2012

Run ‘Revaluation of moving average’ form in “Product information and management module” to check the moving prices of item based on dimensions.

static void SL_FindItemCostPriceAsPerDate(Args _args)


InventDim           inventDimCriteria;

   ItemId                 itemId;

   InventDimParm  inventDimParm;

date                    perDate = mkDate(28,3,2016);

InventOnHand    inventOnHand;


   itemId                 = ‘010100002’;

   inventDimCriteria.inventBatchId = ‘123456’;


inventOnHand    = InventOnhand::newParameters(itemId, inventDimCriteria, inventDimParm);

info(strfmt(‘%1’, inventOnHand.costPricePcs(false, perDate)));



public CostPrice itemCostPrice(ItemId _itemId, InventDimId _inventDimId)
InventDimParm inventDimParm;
InventOnHand inventOnHand;
InventDim inventDim;

inventDim = InventDim::find(_inventDimId);


inventOnHand = InventOnhand::newParameters(_itemId, inventDim, inventDimParm);

return inventOnHand.costPricePcs();


Extra –

public CostPriceAverage runningAvgCostPrice(ItemId _itemId, InventDimId _inventDimId)
InventDim dim;
InventSum inventSum;
inventDim inventDim;
InventTable inventTable;
InventCostPriceCache inventCostPriceCache;
UnitOfMeasureConverter_Product secondaryToInventUnitConverter;
UnitOfMeasureRecId fromUnitOfMeasureRecId;
UnitOfMeasureRecId toUnitOfMeasureRecId;

select firstOnly inventSum
where inventSum.ItemId == _itemId
join inventDim;

if (!inventSum.InventDimId)
dim = InventDim::findDim(inventDim);
if (dim.InventDimId)
inventSum.InventDimId = dim.InventDimId;

inventCostPriceCache = InventCostPriceCache::construct();
inventTable = inventSum.inventTable();

fromUnitOfMeasureRecId = UnitOfMeasure::findBySymbol(inventTable.salesUnitId()).RecId;
toUnitOfMeasureRecId = UnitOfMeasure::findBySymbol(inventTable.inventUnitId()).RecId;
secondaryToInventUnitConverter = UnitOfMeasureConverter_Product::construct();

return Currency::amount(inventCostPriceCache.costPricePcs(inventSum, inventDim) * secondaryToInventUnitConverter.convertValue(1));



Data Copy from one tables to another using Query::insert_recordset()

Hi friends,today is nice day i am feeling bit excited about writing something interesting for technical’s on the blog.

Task : We need to copy Query data(data from different table) into one or more tables.

Solution :  lets just complete this task using Query::insert_recordset().

For explanation purpose lets just take the example in which we had two tables  :
Requirement : We need to copy data of fields Name & description from QueryDemoSource to QueryDemoTarget

Filter :   QueryDemoSource.Active  ==  NoYes:: Yes

Tables Used in Example :

1.QueryDemoSource Table: From where the data need to be copied contains the fields Name,Description,Active(Enum NoYes).

2.QueryDemoTarget  Table:  Destination table for data to be copied to should have fields Name,Description.

Please follow the below given instructions to achieve the same :

1.Build Query .
2.Apply required filter to query.
3.Create field list(Name,Description) to be copied from source table (QueryDemoSource).
4.Specify the mapping from Source to Target Table.
5.Call Query::insert_recordset() method with parameters
b.Map contaning the mapping between the Source field & Target field .
c.Query build in Step 1.

After following above steps ,run the job or class & check the data in the target table.Please find the below job for demo purpose :

Note: insert query.clearAllFields() after q = new Query() line.

Loop through all the fields of a table in X++

static void Job1(Args _args)
SysDictTable dictTable = new SysDictTable(tableNum(PurchLine));
SysDictField dictField;
TreeNode treeNode;
FieldId fieldId = dictTable.fieldNext(0);

while (fieldId)
dictField = dictTable.fieldObject(fieldId);

if (dictField.isSql() && !dictField.isSystem())
treeNode = dictField.treeNode();
info(strFmt(“%1 | %2 | %3”,, // Field name
treeNode.AOTgetProperty(“Label”), // Label id
SysLabel::labelId2String(treeNode.AOTgetProperty(“Label”)))); // Label string

fieldId = dictTable.fieldNext(fieldId);