Dynamics AX Blog - Microsoft Dynamics AX (Axapta) - Page 23

In recent years, i spent a lot of time in developing in the environment of Microsoft Dynamics AX (formerly Axapta). During this time i created a lot of code, from which I could imagine, that it might be very useful for other AX developers too. But I will present also tips and tricks round the powerful ERP system.
Subscribe to RSS feed of this categoryControl editing form fieldsIf you want to control which of the fields on a form are editable, you can use the property allowEdit of the datasource fields. If you have large tables containing a lot of fields, this could be a time-consuming process. So, if you have a form, where the user should only be able to edit one field - in particular case a field from table salesLine -, you could use the following code-example which should be included in the init-method of the datasource. The snippet disallows editing for all fields exept for one field. public void init() 
{ sqlDictionary sqlDictionary; ; super(); while select sqlDictionary where sqlDictionary.tabId == tableNum(salesLine) && sqlDictionary.fieldId != 0 { if(sqlDictionary.name != "dataareaid" && sqlDictionary.name != "recversion" && sqlDictionary.name != "recId" ) { salesline_ds.object(sqlDictionary.fieldId).allowEdit(false); } } salesline_ds.object(fieldNum(salesLine, blocked)).allowEdit(true); } Tested in AX 3.0  | 
Be careful when duplicating companyThat we can duplicate a company is known. The experience of the past few weeks has taught me the following: 
  | 
Working with the calling object of a form (Caller)The following method contains some snippets that can be used to call various functions/methods of the calling object (form). If you change element.args() to e.g. _args and pass the arguments to the method, you can use the code within a class as well. 
void workWithCallingRecord()
{
    common          common;
    object          object;
    formDataSource  formDataSource;
    formRun         formRun;
    inventDim       inventDim;
    salesTable      salesTable;
    int             i;
    ;
    // Call method from calling record
    if( element.args() &&
        element.args().record() )
    {
        common = element.args().record();
        if(common.isFormDataSource())
        {
            info(tableId2Name(common.TableId));
            if(formDataSourceHasMethod(common.dataSource(), identifierStr("someMethod")))
            {
                object = common.dataSource();
                object.someMethod();
            }
        }
    }
 
    // Call method from calling form
    if(element.args() && element.args().caller() && element.args().caller().handle() == className2Id('formRun'))
    {
        formRun = element.args().caller();
        if(sysFormRun::hasMethod(formRun, identifierStr("someFormMethod")))
        {
            object = formRun;
            object.someFormMethod();
        }
    }
    // Get value from calling record
    if( element.args() &&
        element.args().record() )
    {
        common = element.args().record();
        if(common.TableId == tableNum(salesTable))
        {
            info(common.(fieldNum(salesTable, salesId)));
        }
    }
    // Get value from calling datasource (form with multiple datasources)
    if(element.args() && element.args().caller() && element.args().caller().handle() == className2Id('formRun'))
    {
        formRun = element.args().caller();
        for (i = 0; i <= formRun.dataSourceCount(); i++)
        {
            formDataSource = formRun.datasource(i);
            if (formDataSource && formDataSource.table() == tablenum(inventDim))    // Search for specific table
            {
                inventDim = formDataSource.cursor();
                break;
            }
        }
        if(inventDim)
        {
            info(inventDim.InventLocationId);
        }
    }
    // Change data in calling datasource
    if(element.args() && element.args().caller() && element.args().caller().handle() == className2Id('formRun'))
    {
        formRun = element.args().caller();
        for (i = 0; i <= formRun.dataSourceCount(); i++)
        {
            formDataSource = formRun.datasource(i);
            if (formDataSource && formDataSource.table() == tablenum(salesTable))    // Search for specific table
            {
                salesTable = formDataSource.cursor();
                break;
            }
        }
        if(salesTable)
        {
            // Update data
            salesTable.PurchOrderFormNum = "Some value";
            salesTable.update();
        }
    }
    // Refresh calling datasource
    if( element.args() &&
        element.args().record() )
    {
        common = element.args().record();
        if(common.isFormDataSource())
        {
            formDataSource = common.dataSource();
            formDataSource.research(true);
        }
    }
} | 
Dynamics AX: Import Excel fileRecently I was forced to deal with how to read data from an Excel file into AX. Therefore in the following a job with a kind of basic structure, how to solve something like this in X++. 
static void importFromExcel(Args _args) 
{
    Filename                fileNameExcel = "C:\temp\file.xls";
    SysExcelApplication     sysExcelApplication;
    SysExcelWorkbooks       sysExcelWorkbooks;
    SysExcelWorksheets      sysExcelWorksheets;
    SysExcelWorksheet       sysExcelWorksheet;
    SysExcelRange           sysExcelRange;
    SysExcelCells           sysExcelCells;
    SysExcelWorkbooks       sysExcelWorkBooksCollection;
    str                     column_a;
    str                     column_b;
    str                     column_c;
    str                     column_d;
    int                     i = 0;
    #Excel
    ;
    sysExcelApplication = SysExcelApplication::construct();
    sysExcelWorkbooks   = sysExcelApplication.workbooks();
    sysExcelWorkbooks.open(fileNameExcel);
    sysExcelWorksheets  = sysExcelApplication.worksheets();
    sysExcelWorksheet   = sysExcelWorksheets.itemFromNum(1);
    sysExcelRange       = sysExcelWorksheet.rows();
    sysExcelCells       = sysExcelWorksheet.cells();
    try
    {
        ttsbegin;
        while (sysExcelCells.item(i+1, 1).value().variantType() != ComVariantType::VT_EMPTY)  // In der Annahme, dass die erste Spalte nicht leer ist         
        {
            i++;
            column_a = sysExcelCells.item(i, 1).value().bStr();
            column_b = sysExcelCells.item(i, 2).value().bStr();
            column_c = sysExcelCells.item(i, 3).value().bStr();
            column_d = sysExcelCells.item(i, 4).value().bStr();
            // ... do something ...
        }
        ttscommit;
        info("Finished");
        sysExcelApplication.quit();
        sysExcelApplication = null;
    }
    catch (Exception::Error)
    {
        sysExcelApplication.quit();
        sysExcelApplication = null;
    }
} | 
Dynamics AX: Illegal property valueIf you try to change the AllowDuplicates-Property of a table index from No to Yes, the following error message may occur: Illegal property value In this case, presumably, the affected index is registered as PrimaryIndex or ClusteredIndex of the table.  | 
Dynamics AX: Print SalesInvoice through codeUsing the following code you can easily print sales invoice through code. With slight modifications to the code, this is also true for all other sales- and purchase-sided documents. Short example in AX 2009 
static void PrintSalesInvoice(Args _args)
{
   custInvoiceJour     custInvoiceJour;
   SalesFormLetter     salesFormLetter = SalesFormLetter::construct(DocumentStatus::Invoice, false);
   PrintJobSettings    printJobSettings = new PrintJobSettings();
   Args                args = new Args();
   boolean             prompt = true;
   boolean             printIt = true;
   ;
   if (prompt)
   {
       // Dialog
       printIt = printJobSettings.printerSettings('SysPrintForm');
   }
   else
   {
       // Printjobsettings
       printJobSettings.setTarget(PrintMedium::File);
       printJobSettings.format(PrintFormat::PDF);
       printJobSettings.fileName(@'c:	empmyfile.pdf');
   }
   if (!printIt)
   {
       return; 
   }
   salesFormLetter.updatePrinterSettingsFormLetter(printJobSettings.packPrintJobSettings());
   select firstOnly custInvoiceJour
       where custInvoiceJour.salesid == '100001';
   args.record(custInvoiceJour);
   args.caller(salesFormLetter);
   new MenuFunction(menuitemoutputstr(SalesInvoice), MenuItemType::Output).run(args);
}
Short example in AX 4.0 
static void PrintSalesInvoice(Args _args)
{
   custInvoiceJour     custInvoiceJour;
   SalesFormLetter     salesFormLetter = SalesFormLetter::construct(DocumentStatus::Invoice, false);
   PrintJobSettings    printJobSettings = new PrintJobSettings();
   Args                args = new Args();
   boolean             prompt = true;
   boolean             printIt = true;
   salesPrintSetup     salesPrintSetup;
   ;
   if (prompt)
   {
       // Dialog
       printJobSettings = new PrintJobSettings(salesPrintSetup.PrintJobSettings);
       printIt = printJobSettings.printerSettings('SysPrintForm');
       salesPrintSetup.PrintJobSettings = printJobSettings.packPrintJobSettings();
   }
   else
   {
       // Printjobsettings
       printJobSettings.setTarget(PrintMedium::File);
       printJobSettings.format(PrintFormat::PDF);
       printJobSettings.fileName(@'c:	empmyfile.pdf');
   }
   if (!printIt)
   {
       return; 
   }
   salesFormLetter.updatePrinterSettingsFormLetter(printJobSettings.packPrintJobSettings());
   select firstOnly custInvoiceJour
       where custInvoiceJour.salesid == '100001';
   args.record(custInvoiceJour);
   args.caller(salesFormLetter);
   new MenuFunction(menuitemoutputstr(SalesInvoice), MenuItemType::Output).run(args);
}
 | 
  | 
|
  | 
|
  | 
|
                
If you want to run specific forms or classes when Dynamics AX is started, you could use the command-line-param autorun. This parameter awaits a xml-file containing the objects, which should be launched.
The corresponding xml-file startup.xml looks like this:
Additional information are available at MSDN: http://msdn.microsoft.com/en-us/library/aa870082.aspx