Wednesday, December 2, 2015

Multi-Select Lookup Control and grid filteration Using X++

1.Create a Form

2.Go to Design node and then select a StringEdit Control

3.Name the control as Multilookup - Set auto declaration to Yes to access the control using X++

4.Add a button in order to get values on button click

5.Now open the Class Declaration node of the form and write the following code into it

   SysLookupMultiSelectCtrl msCtrl;

6.Override the init method of the form and write the following code in it


Query query = new Query();

QueryBuildDataSource qbds;

super();

//creating query to show customer account and customer name

//the query must contain only those fields that should be visible on the lookup

qbds = query.addDataSource(tableNum(CustTable));

qbds.fields().dynamic(YesNo::No);

qbds.fields().addField(fieldNum(CustTable,AccountNum));

qbds = qbds.addDataSource(tableNum(DirPartyTable));

qbds.fields().dynamic(YesNo::No);

qbds.fields().addField(fieldNum(DirPartyTable,Name));

qbds.relations(true);

//assigning control and query to the class

msCtrl = SysLookupMultiSelectCtrl::constructWithQuery(element, MultiLookup, query);


Note :- if you are using the AOT query you can using the below code

msCtrl = SysLookupMultiSelectCtrl::construct(element, MultiLookup, queryStr(queryname));


7.Now  override the clicked method of the Button

void clicked()
{
    CustTrans           custtrans1;
    CustTable           custtable;
    DirPartyTable       dir;
    List                strlist   = new List(Types::String);
    ListIterator        iterator;
    container           packedList, c,v;
    int i;


    ;

    strlist=strSplit(CustTrans_AccountNum.valueStr(),";");
    iterator = new ListIterator(strlist);
    while(iterator.more()) // Additionally, to move to the next item in a list, you must explicitly call the more and next methods if you are using a list iterator.

    {
       //filtering the grid based on the selected customers and Trans Date.
        while select custtrans1
        where custtrans1.AccountNum ==  iterator.value()               
         && custtrans1.TransDate >= Proj_CustTrans_kkr_FromDate.dateValue()
         && custtrans1.TransDate <= Proj_CustTrans_kkr_ToDate.dateValue()

        {
            Proj_CustTrans_kkr.CustAccount = custtrans1.AccountNum;
            Proj_CustTrans_kkr.Name = DirPartyTable::findRec(CustTable::find(custtrans1.AccountNum).Party).Name;
            Proj_CustTrans_kkr.AmountCur = custtrans1.AmountCur;
            Proj_CustTrans_kkr.TransDate = custtrans1.TransDate;
            Proj_CustTrans_kkr.insert();
        }
        iterator.next(); // Additionally, to move to the next item in a list, you must explicitly call the more and next methods if you are using a list iterator.
    }

    Proj_CustTrans_kkr_ds.research();
    Proj_CustTrans_kkr_ds.refresh();
    CustTrans_ds.research();
    CustTrans_ds.refresh();

    super();


}


Tuesday, December 1, 2015

Importing Unit of Measures of AX 2009 to 2012 using EXCEL.

UNIT_Excel (Importing Units of 2009)
==============================
static void Unit_Excel(Args _args)
{
    Dialog dialog;
    DialogField dialogfield;
    Filename filename;

    SysExcelApplication application;
    SysExcelWorkbooks workbooks;
    SysExcelWorkbook workbook;
    SysExcelWorksheets worksheets;
    SysExcelWorksheet worksheet;
    SysExcelCells cells;

    COMVariantType type;
    int row;
    UnitOfMeasure unitofmeasure,UnitFM;

    ;

    dialog = new dialog("FileOpen");
    dialogfield = dialog.addField(extendedTypeStr(FilenameOpen), 'File Name');
    dialog.run();

    if(dialog.run())
    {
     filename =(dialogfield.value());
    }

    row=1;
    application = SysExcelApplication::construct();
    workbooks = application.workbooks();

    try
    {
        workbooks.open(filename);
    }
    catch (Exception::Error)
    {
        throw error("File cannot be opened.");
    }

     workbook = workbooks.item(1);
    worksheets = workbook.worksheets();
    worksheet = worksheets.itemFromNum(1);
    cells = worksheet.cells();
    do
    {
    row++;
    unitofmeasure.DecimalPrecision=any2int(cells.item(row,1).value().double());
    unitofmeasure.Symbol=cells.item(row,2).value().bStr();
    unitofmeasure.SystemOfUnits=any2int(cells.item(row,3).value().double());
    unitofmeasure.UnitOfMeasureClass=any2int(cells.item(row,4).value().double());
    UnitFM=unitofmeasure::findBySymbol(unitofmeasure.Symbol,true);
        if(UnitFM)
    {
        ttsBegin;
        UnitFM.selectForUpdate(true);
        UnitFM.update();
        ttsCommit;
    }
    else
        unitofmeasure.insert();

    info(strfmt('%1 ', unitofmeasure.RecId ));
    type = cells.item(row+1, 1).value().variantType();

    }
    while (type != COMVariantType::VT_EMPTY);
    application.quit();

}

-===================================================================
UOM_Excel ( Importing Unit of Measures of 2009)
====================================================================

static void UOM_Excel(Args _args)
{
    Dialog dialog;
    DialogField dialogfield;
    Filename filename;

    SysExcelApplication application;
    SysExcelWorkbooks workbooks;
    SysExcelWorkbook workbook;
    SysExcelWorksheets worksheets;
    SysExcelWorksheet worksheet;
    SysExcelCells cells;

    COMVariantType type;
    int row,cnt=0;
    UnitOfMeasureConversion unitOfMeasureConversion, unitofmeasure;
    ;

    dialog = new dialog("FileOpen");
    dialogfield = dialog.addField(extendedTypeStr(FilenameOpen), 'File Name');
    dialog.run();

    if(dialog.run())
    {
     filename =(dialogfield.value());
    }

    row=1;
    application = SysExcelApplication::construct();
    workbooks = application.workbooks();

    try
    {
        workbooks.open(filename);
    }
    catch (Exception::Error)
    {
        throw error("File cannot be opened.");
    }

    workbook    = workbooks.item(1);
    worksheets  = workbook.worksheets();
    worksheet   = worksheets.itemFromNum(1);
    cells       = worksheet.cells();
    do
    {
        row++;
        unitOfMeasureConversion.Product             = EcoResProduct::findByProductNumber(cells.item(row, 1).value().bStr()).Recid;
        unitOfMeasureConversion.ToUnitOfMeasure     = UnitOfMeasure::findBySymbol(cells.item(row, 4).value().bStr()).RecId;

        unitOfMeasureConversion.Factor              = cells.item(row, 3).value().double();

        unitOfMeasureConversion.Numerator           = 1;
        unitOfMeasureConversion.Denominator         = 1;
        unitOfMeasureConversion.FromUnitOfMeasure   = UnitOfMeasure::findBySymbol(cells.item(row, 2).value().bStr()).RecId;
        unitOfMeasureConversion.Rounding            = UnitofMeasureconversionrounding::Nearest;//cells.item(row, 5).value().bStr();
        unitofmeasure = UnitOfMeasureConversion::findByConversion(unitOfMeasureConversion.FromUnitOfMeasure, unitOfMeasureConversion.ToUnitOfMeasure,unitOfMeasureConversion.Product);
        if( unitOfMeasureConversion.ToUnitOfMeasure!=0 &&  unitOfMeasureConversion.FromUnitOfMeasure!=0)
         {
          if(unitofmeasure)
          {
            ttsBegin;
            unitofmeasure.selectForUpdate(true);
            unitofmeasure.update();
            ttsCommit;
          }
          else
             {
            unitOfMeasureConversion.insert();
                 cnt++;
             }
          info(strfmt(' Conversions imported for the products=%1 ', EcoResProduct::findByProductNumber(cells.item(row, 1).value().bStr()).DisplayProductNumber ));

         }
        else
        {
            info(strfmt('Conversions are not imported for products=%1 ',  EcoResProduct::findByProductNumber(cells.item(row, 1).value().bStr()).DisplayProductNumber ));

        }
         type = cells.item(row+1, 1).value().variantType();
    }
    while (type != COMVariantType::VT_EMPTY);
    info(strFmt('No Of Conversions imported are=%1',cnt));
    application.quit();


}

--------------------------------------------------------------------------------------------------------------------------

Below is the method to check the Text format


static void UOM_Excel(Args _args)
{
    Dialog                         dialog;
    DialogField                 dialogfield;
    Filename                    filename;

    SysExcelApplication  application;
    SysExcelWorkbooks  workbooks;
    SysExcelWorkbook    workbook;
    SysExcelWorksheets  worksheets;
    SysExcelWorksheet   worksheet;
    SysExcelCells              cells;
 
    EcoResProduct          ecoResProduct;
    InventTable                inventtable;
    ItemId                        itemid;
 
    COMVariantType      type;
    int                              row,cnt=0;
    UnitOfMeasureConversion unitOfMeasureConversion, unitofmeasure;
    ;

    dialog = new dialog("FileOpen");
    dialogfield = dialog.addField(extendedTypeStr(FilenameOpen), 'File Name');
    dialog.run();

    if(dialog.run())
    {
     filename =(dialogfield.value());
    }

    row=1;
    application = SysExcelApplication::construct();
    workbooks = application.workbooks();

    try
    {
        workbooks.open(filename);
    }
    catch (Exception::Error)
    {
        throw error("File cannot be opened.");
    }

    workbook    = workbooks.item(1);
    worksheets  = workbook.worksheets();
    worksheet   = worksheets.itemFromNum(1);
    cells       = worksheet.cells();
    do
    {
        row++;
     
     
        switch(cells.item(row, 1).value().variantType())
        {
        case COMVariantType::VT_BSTR:
            itemid = strFmt("%1", cells.item(row, 1).value().bStr());
            break;
        case COMVariantType::VT_DECIMAL, COMVariantType::VT_R4, COMVariantType::VT_R8:
            itemid = strFmt("%1", any2int(cells.item(row, 1).value().double()));
            break;
        case COMVariantType::VT_I1, COMVariantType::VT_I2, COMVariantType::VT_I4:
            itemid = strFmt("%1", cells.item(row, 1).value().int());
            break;
        case COMVariantType::VT_UI1, COMVariantType::VT_UI2, COMVariantType::VT_UI4:
            itemid = strFmt("%1", cells.item(row, 1).value().uLong());
            break;
         case COMVariantType::VT_EMPTY:
            itemid = '';
            break;
        default:
            throw error(strfmt('Unhandled variant type (%1).', cells.item(row, 1).value().variantType()));
        }

     
     
     
        if(itemid)
        {
         
        inventtable = InventTable::find(itemid);  
         
        unitOfMeasureConversion.Product             = inventtable.Product;
        unitOfMeasureConversion.ToUnitOfMeasure     = UnitOfMeasure::findBySymbol(cells.item(row, 4).value().bStr()).RecId;

        unitOfMeasureConversion.Factor              = cells.item(row, 3).value().double();

        unitOfMeasureConversion.Numerator           = 1;
        unitOfMeasureConversion.Denominator         = 1;
        unitOfMeasureConversion.FromUnitOfMeasure   = UnitOfMeasure::findBySymbol(cells.item(row, 2).value().bStr()).RecId;
        unitOfMeasureConversion.Rounding            = UnitofMeasureconversionrounding::Nearest;        unitofmeasure = UnitOfMeasureConversion::findByConversion(unitOfMeasureConversion.FromUnitOfMeasure, unitOfMeasureConversion.ToUnitOfMeasure,unitOfMeasureConversion.Product);
     
        if( unitOfMeasureConversion.ToUnitOfMeasure!=0 &&  unitOfMeasureConversion.FromUnitOfMeasure!=0)
         {
          if(unitofmeasure)
          {
            ttsBegin;
            unitofmeasure.selectForUpdate(true);
            unitofmeasure.update();
            ttsCommit;
          }
          else
             {
            unitOfMeasureConversion.insert();
                 cnt++;
             }
          info(strfmt(' Conversions imported for the products=%1 ', inventtable.ItemId));

         }
        else
        {
            info(strfmt('Conversions are not imported for products=%1 ',  inventtable.ItemId));

        }
        }
        else
        {
            info(strfmt('Item not found: %1',cells.item(row, 1).value().bStr()));
        }
         type = cells.item(row+1, 1).value().variantType();
    }
    while (type != COMVariantType::VT_EMPTY);
    info(strFmt('No Of Conversions imported are=%1',cnt));
    application.quit();


}


Saturday, November 21, 2015

How to open the Child form using X++

Error :- Dynamics AX form requires an active buffer

Here is the code for above explanation: -

        Args                    argsForm;
        FormRun             formRun;
        FormRun             subformRun;
        ;
   

        //Open Picking List form
        argsForm = new Args(formstr(ProdJournalTable));
        argsForm.record(ProdJournalTable::find(prodJournalTable.JournalId));
        formRun = classFactory.formRunClass(argsForm);
        formRun.init();
        formRun.run();


        //Now open sub-form (Production Journal Lines)
        argsForm = new Args(formstr(ProdJournalTransBOM));
        //Here you can mention the parent form instance as an active buffer
        argsForm.caller(formRun);    
        argsForm.record(ProdJournalTable::find(prodJournalTable.JournalId));

        subformRun = classFactory.formRunClass(argsForm);
        subformRun.init();
        subformRun.run();
        formRun.close(); //Now close the parent form.
        subformRun.wait(); //This halts your programme execution.

Wednesday, November 4, 2015

How to change the Infolog limit in AX 2012 ?

Hi Folks !

Recently I got a requirement to import a list of Items in AX  and  also I have to make a list of Imported item. Well the problem was the list exceed 10000 Limit.

Default limit of Infolog messages is 10000. I have found a solution for this limit.

You can change the value of  MaxErrors macro in viewBuild() method of Info class


Hope this information will help you

Friday, October 16, 2015

An Unbalanced X++ TTSBEGIN/TTSCOMMIT pair has been detected

Issue :- I was trying to import the class in the application and when I click on any button to import or cancel the import I was getting this error as An unbalanced X++ TTSBEGIN/TTSCOMMIT. which means there are too many TTSBEGIN/TTSCOMMIT  statements.

And the TTS level is "2".

At this unable to import the class as the dialog box throws error on all the buttons.

To resolve this error you need to remove all the extra TTSBEGIN/TTSCOMMIT from the code.

This can be done with the simple Job which is return below.


To resolve this error this TTS level should be ZERO, Run this job to get rid of that error, this job will find the tts level where its greater than zero and make it zero by calling TTSABORT.
static void TheAxaptaResetTTS(Args _args)
{
    while (appl.ttsLevel() > 0)
    {
        info(strfmt("Level %1 aborted",appl.ttsLevel()));
        ttsAbort;
    }
}


Understanding TTSBEGIN /TTSCOMMIT 


ttsBegin: marks the beginning of a transaction. This ensures data integrity, and guarantees that all updates performed until the transaction ends (by ttsCommit or ttsAbort) are consistent (all or none).

ttsCommit: marks the successful end of a transaction. This ends and commits a transaction. MorphX guarantees that a committed transaction will be performed according to intentions.


I got the above information from the below source :
https://community.dynamics.com/ax/b/axaptavsme/archive/2013/08/29/error-an-unbalanced-x-ttsbegin-ttscommit-pair-has-been-detected-in-ax

above blog is very helpful you will get the help for most of the solutions.


Tuesday, October 13, 2015

Table Relations in AX 2012

What is Table Relation ?

A table relation associates two tables that contain related information. Usually the primary key field of one table appears as a foreign key field of the related table. The table with the primary key is called the parent table. The table with the foreign key is called the child table.

For example, a parent table named Department can have a departmentId field as its primary key. A child table named Employee can have a departmentId field as a foreign key.

Detail Explanation :- https://msdn.microsoft.com/en-us/library/aa675395.aspx


The foundation of Microsoft Dynamics AX is the relational database. Relationships can be created between tables that contain related data. In Microsoft Dynamics AX, the relationship between tables is called a relation.

Relations in Microsoft Dynamics AX:
  • Keep the database consistent (enforce referential integrity).
  • Are used by the Auto Join system in forms.
  • Enable the look up of values in other tables (through lookup list/selection list boxes and the View details Form command).
  • Are used to validate data.
  • Automatically propagate changes from one table to another.
  • Auto-define table relationships in queries.

Table relations are most commonly used in form fields to enable the look up of information in another table. If a table relation exists, the lookup button can be used to display a lookup list of values for a particular field.

A table relation is created by specifying one or more fields in a table that contain the same value in a related table. The matching fields typically have the same name in each table.

For example, a SalesOrder table containing orders might have a field called SalespersonID, which identifies the salesperson that took the order. The Salesperson table, containing the names of sales people, would also have a field called SalespersonID.

To create a table relation, specify that the SalesOrder.SalespersonID field is related to the Salesperson.SalespersonID field.

Source :- https://msdn.microsoft.com/en-us/library/bb190076.aspx

Adding a Relation to a Table :-
  1. In the AOT, move to Data Dictionary > Tables, and then expand the table that the relation will be added to.
  2. Right-click the Relations node, and then select New Relation.
  3. Right-click the newly added relation, and then select Properties.
  4. Set the name of the new relationship by modifying the Name property.
  5. In the Table property, select the related table.
  6. Use the Validate property to determine whether the relation should be used to validate data when information is entered into forms.
  7. Right-click the new relation, select New, and then click one of the following:
  • Normal to specify relation fields without conditions.
  • Field fixed to specify relation fields to restrict the records in the primary table.
  • Related field fixed to specify relation fields that restrict the records in the related table.
  • ForeignKey to specify a correspondence between a foreign key field in the present table to the primary key field in another parent table.

Conditional Table Relations :-

Define conditional table relations to filter the records in either the primary or the related table. Following are the conditional table relations that can be specified when you define the fields in a table relation:

  • Field fixed
  • Related field fixed
You create a conditional relation by right-clicking the  AOT > Data Dictionary > Tables > YourTable > Relations > YourRelation node. Then click either Field fixed for Related field fixed.

Understanding the Conditions :-

Field Fixed :- Table.Field == <EnumValue>

Restricts the records selected in the primary table. Only records that meet the condition are selected.
The condition is ANDed with your relation.

Related field fixed :- (<EnumValue> == Table.Field)

Restricts the records selected in the related table. Only records that meet the condition are selected.
The condition is ANDed with your relation.



ForeignKey Relation :

ForeignKey to specify a correspondence between a foreign key field in the present table to the primary key field in another parent table.

There are 2 ways of creating foreign key relation:


  • PrimaryKeyBased- Primary key is the unique index specified in the Parent table PrimaryIndex property. It can consists of 1 or more fields


  • SingleFieldAlternateKeyBased- Alternate key is an unique index specified in the Parent table, with its AlternateKey property set to Yes. However, to be eligible for use for creating foreign key relation, The alternate key can only consist of a single field.

Normal Relation :

To specify relation fields without conditions.

Sunday, October 4, 2015

Compile , CIL (Incremental CIL and Full CIL) in AX 2012

well developers new to AX always get hard time to understand compile , Full CIL and CIL , I have jotted down few points from different sources to understand these concepts

Compile :- When the Microsoft Dynamics AX application is compiled, its X++ source code is translated into a machine-executable format that can be interpreted by the Microsoft Dynamics AX server and clients.

What is CIL? 

CIL stands for Common Intermediate Language and it works together with the CLI or Common Language Infrastructure, which is basically a set of rules on programming languages that will compile with the CIL.



Picture is taken from the source:- http://axwonders.blogspot.in/2013/04/ax-2012-cil-how-does-it-work.html, which explains the same process in detail

The Common Language Runtime (CLR) that ships with .NET understands the Common Intermediate Language and knows how to execute that code.  The CLR does not need to understand all of the different languages (like C#, VB or F#) it needs to only understand the one language they all get mapped down to, CIL.

In AX you program in X++ and the equivalent of AX's CLR is the kernel.  When you build or compile your X++ code it traditionally gets mapped down to a p-code language that the kernel understands and knows how to execute.

In AX 2012 for certain classes that is what has changed. Now when you compile the X++ code gets mapped down to the Common Intermediate Language.  Then the CLR understands what the code says and executes it -here kernel is not needed.


Write, save, and compile your X++ class :- The X++ source code for your class is automatically compiled into p-code when you save the source in the AOT.

Compile the p-code into CIL :- X++ is compiled into p-code. The p-code can be compiled into CIL by the following menu:

AOT > Add-ins > Incremental CIL generation from X++

Note:- The CIL generation process writes files to an AOS installation subdirectory. The directory path could resemble the following: C:\Program Files\Microsoft Dynamics AX\60\Server\MicrosoftDynamicsAX\bin\XppIL\


we have two types of CIL compilations, the incremental CIL and the full CIL compilation.

Full CIL :- generate CIL is about to convert the p-code into CIL, referred to as the byte code which, at run time, is used by the CLR to convert into native code for execution on the computer. It is easier to understand that a full CIL generation involves converting all p-code into CIL, finally it converts to the binary Language.

Incremental CIL :- incremental CIL generation involves only the “changed” p-code artifacts that need  to be converted into target CIL. Incremental CIL would compile only the objects that were modified since the last incremental compilation.

In short the major difference between the two of them is that the incremental CIL would compile only the objects that were modified since the last incremental compilation.

Note :- if the installation uses multiple instances of Application Object Server (AOS), all AOS instances must be stopped and then restarted. This causes the AOS instances to load the updated assembly.




How to enable the dimension fields based on the Item selected on the form.

[Form] public class KMTShipFromWarehouses extends FormRun {     InventDimCtrl_Frm_EditDimensions        inventDimFormSetup;     /// ...