Tuesday, January 19, 2016

AX 7 - Missing Menus even with Admin User

Hello All,
Recently we faced an issue while implementing AX 7 for one of our customer. The issue was with the menu Items displayed on the left hand side of the browser. We simply couldn't see the menu even though we logged in using the System administrator account. All it displayed was few menu's hiding the rest. Please refer to the image below for more clarity.
Logged in using the system administrator account
After doing lot of re-search we figured out that the issue is caused because Commerce essentials configuration in the license configuration for AX 7 was enabled due to this the system will only enable basic functionalities related to Retail and hence the menu was not being displayed.
Then the next issue was that we were not able to navigate to Licence configuration page to disable the Commerce essentials configuration since the menu was not displayed. The workaround to access the page is to add the following piece of string highlighted in bold after the main url.
https://devaos.cloudax.dynamics.com/?cmp=DAT&mi=SysConfiguration
This will take you to License configuration page and then in the license configuration page disable the Commerce essentials key, logout and Log in again. Now everything should be fine. You will again see the menus in AX :)

Happy Daxing :).Watch out for my next post 

Monday, September 9, 2013

Find print job settings specified on a Customer for Reports

Hi Friends,
Recently I came across a requirement where in I had to print AX 2012 collection letter report in PDF format and attach it to a mail Item and send it across to the customer. The requirement here was that this functionality has to be triggered on a click of button which was pretty normal but the real catch here was that the email ID should be fetched from the customers print job settings and not a normal setup, In standard system these settings can vary according to journals. I did some research and found out a way to find print job settings of customer for  collection letter journal Report. Here is the code, you can use this code for finding print job settings of many important system reports such as Invoice etc....



Static void findPrintJobSettings(Args _args)

{

    FormLetterReport formletterReport;

    PrintMgmtPrintSettingDetail settingDetail;

    SRSPrintDestinationSettings destination;

    CustCollectionLetterJour    jour;

    CustTable                   custTable;

    select jour where jour.RecId    ==  11290923078;

    select custTable  where custTable.AccountNum == "2014";

    formLetterReport = FormLetterReport::Construct(PrintMgmtDocumentType::

                                                                                     CustCollectionLetter);
                                     
    formLetterReport.parmPrintType(PrintCopyOriginal::OriginalPrint);
  
    formLetterReport.loadPrintSettings(jour,custTable,

                                                              jour.LanguageId,

                                                             jour.CollectionLetterNum);


    while(formletterReport.moveNextPrintSetting())

    {

        settingDetail   =   FormLetterReport.getCurrentPrintSetting();

        destination =   settingDetail.parmPrintJobSettings();
    
        print destination.printMediumType();

        print destination.emailTo();
 
        print destination.numberOfCopies();

        pause;

     }

}

 



 
 

Tuesday, June 28, 2011

Con2str and str2con functions in the Global Class

Many a times we use the functions which are available in the global class of AX.
2 important methods which we normally use during the import of text file or CSV file is con2str() and str2con() functions. Both these functions have limitations of use .

With respect to con2str it is that the string returned from the container cannot exceed more than 1000 char and with respect to the str2con the limitation is that chopps of the zero added before the string for example if you add str2con("00001,0002",",") then the entry in the container would be 1 and 2 respectively at position 1 and 2 of the container . This creates an issue where the Items in the system starts with the 0.

So I twisted both the functions slightly to get our desired o/p
i.e. String greater than 1000 char with con2str() method and
inclusion of 0 with str2con() method.

Here is what I changed :

static str con2strwithchange(container c, str 10 sep = ',')
{
    int idx = 0;
    int len = conlen(c);
    str tmp;
    str retStr;
    ;
   while (idx < len)
  {
       idx += 1;
      if (retStr)
      retStr += sep;
      tmp = conpeek(c,idx);
      retStr += tmp;
  }
  return retStr;
}

static container str2conChanged(str _value, str 10 _sep = ',')
{
      int length = strlen(_value);
      int i = 1;
      int j = strscan(_value, _sep, 1, length);
      container ret;
      void add2Ret(str _current)
      {
           // v-artemt, 26 Jul 2004, PS#: 1741
          //if (match('<:d+>', _current))
         // ret += str2int(_current);
         //else
         ret += _current;
       }
      ;
      while (j)
     {
          add2Ret(substr(_value, i, j-i));
          i = j+1;
         j = strscan(_value, _sep, i, length);
     }
     add2Ret(substr(_value, i, length-i+1));
     return ret;
}

Tuesday, December 28, 2010

Creating a SalesOrder through .net applications or BC classes

Sometimes it would be necessary for us to create the SalesOrder through the .net application or some third party application at that time we need to make use of BC classes to create SalesOrder. Here is a small snipeet for creating the salesOrder through AXBC classes.

static void salesOrder(Args _args)
{   

       AxSalesTable axSalesTable;
       AxSalesLine axSalesLine;
       AxInventDim_SalesLine axInventDim;
       NumberSequenceReference numberSequenceReference;
       NumberSeq numSeq;
       SalesTable salesTable;
       SalesId salesId;
       ;
       ttsbegin;
       numberSequenceReference = SalesParameters::numRefSalesId();
       numSeq = new NumberSeq();
       numSeq = NumberSeq::newGetNum(numberSequenceReference,true);
       salesId = numSeq.num();
       axSalestable = AxSalesTable::construct();
       axSalesTable.parmCustAccount('100123');
       axSalesTable.salesTable().initFromCustTable();
       axSalesTable.salesTable().initValue();
       axSalesTable.salesTable().initFromContactInfo();
      axSalesTable.parmSalesId(salesId);
       if(!axSalesTable.salesTable().validateWrite())
       {
            numSeq.abort();
            break;
       }
       else
       {
           numSeq.used();
           axSalesTable.save();
        }
        SalesTable = SalesTable::find(salesId);
        axSalesLine = AxSalesLine::construct();
        axSalesLine.parmSalesId(salesId);
        axSalesLine.salesLine().initValue();
        axSalesLine.salesLine().initFromSalesTable(SalesTable);
        axSalesLine.parmItemId('1121');
        axSalesLine.salesLine().initfrominventTable();
        axInventDim = AxInventDim_SalesLine::newAxSalesLine(axSalesLine);
        axInventDim.parmInventSizeId('42');
        axInventDim.parmInventLocationId("21");
        axInventDim.parmConfigId("HD");
        axInventDim.parmInventColorId('01');
        axInventDim.parmInventSiteId('2');
        axInventDim.setInventDimId();
        axSalesLine.axInventDim(axInventDim);
        axSalesLine.save();
        ttscommit;
    
}

Getting the list of datasource from the form

Sometimes may be there would be need to get the names of the datasources used in the form . Here is a small snippet that would get you the list of the data source 

static void datasources(Args _args)
{
        FormRun formRun;
        FormBuildDataSource fbds;
        Args args = new Args();
        Counter i;
         ;
         args.name('Salestable'); //FormName
         formRun = classFactory.formRunClass(args);
         for (i = 1; i <= formRun.form().dataSourceCount(); i++)
         {
          fbds = formRun.form().dataSource(i);
          info(new DictTable(fbds.table()).name());
          }
}

The output of the following code is

Thursday, December 23, 2010

Creating a new form using code

static void CreateForm_usingCode(Args _args)
{
    Form form;
    FormRun formRun;
    Args args;
    FormBuildDesign formBuildDesign;
    FormBuildControl formBuildControl;
    FormBuildTabControl formBuildTabControl;
    FormBuildTabPageControl formBuildTabPageControl;
    FormBuildGridControl formBuildGridControl;
    FormBuildDatasource formBuildDatasource;
    FormBuildStringControl formString;
    ;
    form = new Form();
    formBuildDatasource = form.addDataSource(tableStr(CustTable));
    formBuildDesign = form.addDesign('design');
    formBuildTabControl = formBuildDesign.addControl(FormControlType::Tab, 'Tab1');
    formBuildTabPageControl = formBuildTabControl.addControl(
                                                    FormControlType::TabPage,  TabPage');
    formBuildGridControl = formBuildTabPageControl.addControl(FormControlType::Grid, 'Grid');
    formString = formBuildGridControl.addDataField(formBuildDatasource.id(),
                                                                                      fieldNum (CustTable,           Accountnum));
    formString.label("Customer Account");
    args = new Args();
    args.object(form);
    formRun = classFactory.formRunClass(args);
    formRun.init();
    formRun.run();
    formRun.wait();
}

Getting the List of Private and Shared projects from the Projects node using X++.

For retreiving the list of projects we cannot use Treenode. We should first use infolog.projectrootnode() to get the root node for projects and then proceed with the treenode iterator to get the list of the rest. Below is the code that will display the list of Private and Shared Projects from the project node.

static void GetProjects(Args _args)
{
     ProjectListNode projectListNode;
     treenodeIterator iterator,projectiterator;
     TreeNode treenodeprivate,treenodeprivateprojects,treenodeShared,treenodesharedprojects;
     int i;
     ;
     projectListNode = infolog.projectRootNode();
     treenodeprivate = projectListNode.AOTfirstChild();
     iterator =treenodeprivate.AOTiterator();
    setprefix("Private projects");
    for(i = 1; i<=treenodeprivate.AOTchildNodeCount();i++)
    {
            treenodeprivateprojects = iterator.next();
            info(findproperty(treenodeprivateprojects.AOTgetProperties(),"Name"));
     }
     treenodeshared = infolog.projectRootNode().AOTfindChild('Shared');
     projectiterator = treenodeshared.AOTiterator();
     setprefix("Shared Projects");
     for(i=1; i<= treenodeshared.AOTchildNodeCount();i++)
     {
            treenodesharedprojects = projectiterator.next();
            info(findproperty(treenodesharedprojects.AOTgetProperties(),"Name"));
      }
}
Attached is the Output of the following Job: