Operations Maintenance in Microsoft Dynamics AX

Recently I have got a requirement of having a possibility to update several values for selected Operation in AX 2012. This is not an inbuilt feature of AX 2012 but this was a client requirement for providing the possibility to update several values for selected Operation according to given parameter settings.

In my requirement, it was required to create two forms which include a setup form known as Data Maintenance Setup Form where we can specify the tables and fields of selected table to be updated. This form is basically a Parameter settings form to control what can be updated. The form should look like this.


As you can see we have two sections of form .In first section you can choose the name of Table which you want to update and in second section you will have all the fields of above selected table which is required to be updated with new value on the basis of some criteria.

The second form is Operation Maintenance Form where we will define the condition on basis of which the mentioned new value will be updated in the fields that has been selected in Data Maintenance Form. This Operation Maintenance Form will update RouteOpr Table. Since I am talking about Operations here this RouteOpr table is taken into consideration but we can add other tables also and extend the functionality for other Tables as well. This Form should look like this :


Development :

Creation of Data Maintenance Setup Form:

  • I have created two Tables :
    • AAFTableStoreOperations :TableIDNumber ,TableName(uses enum AAFTableNameOperations where you can add n no. of tables in case you want to extend the functionality other than for operations.)
    • AAFFieldStoreOperations: FieldName, TableIDNumber, TableName
    I have used a Splitter form to create my Data Maintenance Setup Form which has two tables in data source:
  • I have written following code on modified method of my Table Name Control
To get the lookup of Field name on Fieldname Control from above selected Table , I have used following code :
Creation of Operation Maintenance Form:

This form is a dialog Form and is created with the help of dialog class. Following are the methods created and code behind it:


I am attaching the code below for this class:

public boolean canGoBatch() { return true; }

This method dialog() gives desired user interface fields for use:

public Object dialog() { FormStringControl fieldNamecontrol,tableNameControl; ; dialog = super(); dlgTableName = dialog.addFieldValue(enumStr(AAFTableNameOperations),tableEnum); namefield = dialog.addField(extendedTypeStr(Name),"@SYS8498"); dlgvalueUpdate = dialog.addField(extendedTypeStr(Name),"@SYS68002"); fieldNamecontrol = namefield.control(); tableNameControl = dlgTableName.control(); fieldNamecontrol.registerOverrideMethod(methodStr(FormStringControl,lookup),methodStr(AAFOperationsMaintain,lookup),this); tableNameControl.registerOverrideMethod(methodStr(FormStringControl,modified),methodStr(AAFOperationsMaintain,fld3_1_modified),this); dialog.allowUpdateOnSelectCtrl(true); return dialog; }

This method allows you to select table which are set in Data Maintenance Form:

public void dialogSelectCtrl() { tablename = enum2Symbol(enumNum(AAFTableNameOperations),dlgTableName.value()); super(); } public void fld3_1_modified(FormStringControl _control) { boolean isFieldModified; Query query; QueryBuildDataSource qbds; ; isFieldModified = _control.modified(); tablename = enum2Symbol(enumNum(AAFTableNameOperations),dlgTableName.value()); this.parmselectedTable(tablename); if(isFieldModified) { namefield.value(''); query = new Query(); if(tablename == enum2str(AAFTableNameOperations::RouteOpr)) { qbds = query.addDataSource(tableNum(RouteOpr)); } else if(tablename == enum2str(AAFTableNameOperations::RouteOprTable)) { qbds = query.addDataSource(tableNum(RouteOprTable)); } queryRun = new QueryRun(query); } } public boolean getFromDialog() { selectedTable = enum2Symbol(enumNum(AAFTableNameOperations),dlgTableName.value()); fieldName = namefield.value(); newValue = dlgvalueUpdate.value(); return super(); } public void initParmDefault() { Query query; QueryBuildDataSource qbd; super(); query = new Query(); qbd = query.addDataSource(tableNum(RouteOpr)); queryRun = new QueryRun(query); }

This method will give the lookup of Fields for the table selected and setup in Data Maintenance Form:

public Types ListFields(TableName _tableName, str _fieldName) { DictField dictField; DictTable dictTable; Types type; ; dictTable = new dictTable(tableName2Id(_tableName)); fieldId = dictTable.fieldName2Id(_fieldName); if (fieldId) { dictField = new DictField(tableName2Id(_tableName), fieldId); if (dictField && !dictField.isSystem()) { type = dictField.baseType(); } } return type; } public void lookup(FormStringControl _control) { SysTableLookup sysTableLookup = SysTableLookup::newParameters(Tablenum(AAFFieldStoreOperations),_control,true); Query query = new Query(); QueryBuildDataSource QBDS; SysTableLookup.addLookupfield(fieldnum(AAFFieldStoreOperations,FieldName),true); QBDS = query.addDataSource(Tablenum(AAFFieldStoreOperations)); QBDS.addRange(fieldnum(AAFFieldStoreOperations,TableName)).value(queryvalue(tablename)); sysTableLookup.parmQuery(query); systableLookup.performFormLookup(); } public container pack() { return [#CurrentVersion, #CurrentList, queryRun.pack()]; } public str parmselectedTable(str _selectedTable = selectedTable) { selectedTable = _selectedTable; return selectedTable; } public QueryRun queryRun() { return queryRun; }

Here in run () we are writing the logic for the value update of any type:

public void run() { RouteOprTable routeOprTable; RouteOpr routeOpr; Types type; DictEnum dictEnum; DictField dictField; super(); type = this.listFields(selectedTable,FieldName); while(queryRun.next()) { ttsBegin; if(selectedTable == enum2str(AAFTableNameOperations::RouteOpr)) { routeOpr = queryRun.get(tableNum(RouteOpr)); routeOpr.selectForUpdate(true); switch (type) { case Types::String: routeOpr.setFieldValue(FieldName,newValue); break; case Types::Enum: dictField = new DictField(tableName2Id(selectedTable), fieldId); dictEnum = new DictEnum(dictField.enumId()); routeOpr.setFieldValue(FieldName,dictEnum.name2Value(newValue)); break; case Types::Integer: routeOpr.setFieldValue(FieldName,str2int(newValue)); break; case Types::Real: routeOpr.setFieldValue(FieldName,str2num(newValue)); break; case Types::Date: routeOpr.setFieldValue(FieldName,str2date(newValue,123)); break; case Types::Int64: routeOpr.setFieldValue(FieldName,str2int64(newValue)); break; } routeOpr.doUpdate(); } if(selectedTable == enum2str(AAFTableNameOperations::RouteOprTable)) { routeOprTable = queryRun.get(tableNum(RouteOprTable)); routeOprTable.selectForUpdate(true); switch (type) { case Types::String: routeOprTable.setFieldValue(FieldName,newValue); break; case Types::Enum: dictField = new DictField(tableName2Id(selectedTable), fieldId); dictEnum = new DictEnum(dictField.enumId()); routeOprTable.setFieldValue(FieldName,dictEnum.name2Value(newValue)); break; case Types::Integer: routeOprTable.setFieldValue(FieldName,str2int(newValue)); break; case Types::Real: routeOprTable.setFieldValue(FieldName,str2num(newValue)); break; case Types::Date: routeOprTable.setFieldValue(FieldName,str2date(newValue,123)); break; case Types::Int64: routeOprTable.setFieldValue(FieldName,str2int64(newValue)); break; } routeOprTable.doUpdate(); } ttsCommit; } info(strFmt("ABC",FieldName,newValue)); } boolean showQueryValues() { return true; } public boolean unpack(container _packedClass) { Version version = runbase::getVersion(_packedClass); Container packedQuery; switch (version) { case #CurrentVersion: [version, #CurrentList, packedQuery] = _packedClass; if(packedQuery) queryRun = new QueryRun(packedQuery); break; default: return false; } return true; } public boolean validate(Object _calledFrom = null) { if (!selectedTable || !fieldName || !newValue) { return checkFailed("ABC”); } return true; } server static AAFOperationsMaintain construct() { return new AAFOperationsMaintain(); } public static void main (Args _args) { AAFOperationsMaintain dataMaintain; dataMaintain = AAFOperationsMaintain::construct(); if(dataMaintain.prompt()) { if (box::yesNo("ABC", dialogButton::Yes, "@SYS114651") == dialogButton::Yes) { dataMaintain.run(); } } }

This is how we can update the field of any table with new value on certain condition using this code.

Hope you all have understood the concept. Feel free to ask any questions related on Microsoft dynamics AX development please contact us.

Tutorial : Plugin System in Magento 2

Tutorial : Plugin System in Magento 2

Magneto development services provider will explain plugin system in Magento 2. You will learn the way to use magento 2 plugins from the basics. Read and discover how professionals do it.

You will learn through this article how to use Magento 2 plugins that modify the behavior of all public functions without overloading the PHP class (block, model etc.) the container.

What are plugins?
To avoid having to override a class to modify a simple, Magento 2 plugins provides a mechanism to effectively manage this type of "rewriting" as well as to minimize conflicts between extensions.

Limitations plugins
To date, plugins can only be used for rewriting public methods and are therefore subject to the following limitations:
1) final methods
2) non-public methods (protected or private)
3) static methods
4) Constructor ( _construct)
5) virtual Types

Types plugin
Magento provides three "types" of different plugins:
1) before: Change the arguments provided to a method
2) around: Change the behavior of a method
3) after: To "rework" the output of a method

Declaration of a plugin
The declaration of any plugin must be done in the file di.xml of your module. This file can be placed, depending on its use, either within the directory etcyour module (plugin to use the backend and frontend) or in etc/frontend

(limited use in frontend) or etc/adminhtml(limited use in backend):

<config> <typename="{observer_type}"> <pluginname="{plugin_name}"type="{plugin_type}"sortOrder="{plugin_order}"disabled="{plugin_disabled}"/> </type> </config>

The following can be specified:
1) observer_type: The class name, or virtual interface type you want to observe
2) plugin_name: The name of the plugin (eg. catalog_product_custom_plugin)
3) plugin_type: The name of the class or type used by the virtual module (ex.Vendor\Module\Plugin\ModelNamePlugin)
4) plugin_order: The order in which the plugin will run. Very useful to effectively manage the execution order of several plugins overloading the same method (see "Execution Order" below for details)
5) plugin_disabled: This parameter can be set trueif you want to disable the plugin

Execution order of the plugins

When multiple plugins rewriting the same method exist, the following order of performance will be followed by Magento:
1. The type of plugin beforethat has the highest priority (= the one with the least sortOrder)
2. The type of plugin aroundthat has the highest priority (= the one with the least sortOrder)
3. The other type of plugins beforebased on their priority (from smallest to largest sortOrder)
4. The other type of plugins aroundbased on their priority (from smallest to largest sortOrder)
5. The type of plugin afterthat has the lowest priority (= the one with the largest sortOrder)
6. The other type of plugins afterbased on their priority (largest to smallest sortOrder)

Example plugins
To change the settings passed to a function, it is necessary to create a methodbefore[methodName]in your plugin (which [methodName]corresponds to not the method you want to change, for example SetNamefor a method named setName).

The method created within your plugin parameter must take the class which includes the function you want to change and its various parameters. Example of method overloading setNameclass \Magento\Catalog\Model\Product:

<?php namespaceMy\Module\Plugin; classProductPlugin { publicfunctionbeforeSetName(\Magento\Catalog\Model\Product $subject, $name) { return['('. $name. ')']; } }

In this example, the product name passed in the argument $namewill be automatically enclosed in parentheses.
As you have probably noticed, the type of plugins beforehave returned an array containing all the parameters of the function.

To change the behavior of a function, a method around[methodName]must be created within your plugin (which [methodName]corresponds to not the method you want to change, for exampleSavefor a method named save).

The method created within your plugin parameter must take the class which includes the function you want to change and a second type parameter \Closurecorresponding to the original method.

Example of method overloading saveclass \Magento\Catalog\Model\Product:

<?php namespaceMy\Module\Plugin; classProductPlugin { publicfunctionaroundSave(\Magento\Catalog\Model\Product $subject, \Closure $proceed) { $returnValue= $proceed(); if($returnValue) { $this->doSomething(); } return$returnValue; } }

In this example, we execute line 9 will recover the original method and the return value. If it is defined, a third function, called here doSomething, will be executed.

Finally, we return line 13 returning the original method.

To change the return of a function, it is necessary to create a method after[methodName]in your plugin (which [methodName]corresponds to not the method you want to change, for exampleGetNamefor a method named getName).

The method created within your plugin parameter must take the class which includes the function you want to change and a variable $resultthat will contain the result of the original method.

Example of method overloading getNameclass \Magento\Catalog\Model\Product:

publicfunctionafterGetName(\Magento\Catalog\Model\Product $subject, $result) { return'|'. $result. '|'; }

In this example, the return of the original method, which is here in the name of the product, will be surrounded by "| ".

The definition, limitations and uses of magento 2 plugins shared by magento developers from India for reference purpose only. You can ask for more info on the Magento 2 plugins in your comments.

Read More :
1) Top 7 Extension for Magento 2 Store
2) Hire Magento developers to get your website ready for mobile
3) Magento Pro Tip: Speed Up Content Deployment within Magento 2
4) Tutorial : Magento 2 Promotional Product Markers