Thursday, October 12, 2017

Open specific AX project by code

    TreeNode    tn = SysTreeNode::getSharedProject();

    tn = tn.AOTfindChild("projectNAme");
    tn.AOTrun();

Friday, September 22, 2017

Add path delimiter for file paths in the field modified value

I found this really interesting way to make sure that the file paths have a forward slash in the end when modifying file paths is to add the following code in the table modified field method


public void modifiedField(FieldId _fieldId)
{
    #File
    super(_fieldId);

    switch (_fieldId)
    {
        (fieldNum(HcmSharedParameters, YourField )):
            // Remove leading and trailing whitespace
            this.(_fieldId) = strltrim(strrtrim(this.(_fieldId)));

            // Add trailing slash if missing
            if (this.(_fieldId) && substr(this.(_fieldId), strlen(this.(_fieldId)), 1) != #FilePathDelimiter)
            {
                this.(_fieldId) = this.(_fieldId) + #FilePathDelimiter;
            }
            break;
    }
}

Wednesday, June 7, 2017

These methods have hardcoded report layouts.


Make sure to look here and confirm which report to modify when modifying standard reports

  • Classes\PrintMgmtDocType\getDefaultReportFormat
  • \Data Dictionary\Tables\PrintMgmtReportFormat\Methods\populate
  • \Data Dictionary\Tables\SRSReportDeploymentSettings\Methods\populateTableWithDefault

Wednesday, May 10, 2017

Run SSRS report using code in AX 2012

The following code lets you run reports using x++

       SrsReportRunController          controller  = new SrsReportRunController();
    WHSWorkInquiryPurchContract     contract    = new  ReportContract();
    SRSPrintDestinationSettings     settings;
    SalesParameters                 salesParameters =  SalesParameters::find();

    // Define report and report design to use
    controller.parmReportName(ssrsReportStr(SalesInvoice, Report));

    // Use execution mode appropriate to your situation
    controller.parmExecutionMode(SysOperationExecutionMode::Synchronous);

    // Suppress report dialog
    controller.parmShowDialog(false);

    // Explicitly provide all required parameters
    contract.parmPurchId(_purchId);
    controller.parmReportContract().parmRdpContract(contract);

    // Change print settings as needed
    settings = controller.parmReportContract().parmPrintSettings();


   if(salesParameters.PrintToScreen) // if print to screen
    {
        settings.printMediumType(SRSPrintMediumType::Screen);

        controller.startOperation();
    }
    else  // else print to printer using a printer name from parameters
    {
        if(salesParameters.POPrinterName)
        {
            settings.printerName(salesParameters.POPrinterName);
            settings.printMediumType(SRSPrintMediumType::Printer);

            controller.startOperation();
        }
   }



Tuesday, March 7, 2017

Restore DB on a sql cluster

This post like many other is for self reference. I recently had a requirement to restore a UAT model to a prod environment and prod was running as a sql cluster. The steps I followed are

1)Remove the db from availability group of primary
2)do the restore to the prod as usual
3)Delete db from the secondary server instance. Yup delete it as it will be restored from the primary
4)Change recovery mode to full mode from properties->Options
5)Take backup
6)Add database to availability group
7) Make sure you have access to the staging path, which needs to be a shared location accessible by both servers
8)Press next next and ok.

Tuesday, February 21, 2017

Add complex range in AOT queries

Before explaining this, a disclaimer: Microsoft clearly states to not have complex queries in the AOT form because of performance issue.

In the following example, I wanted to write the range (InventTrans.StatusReceipt==Purchased ) || InventTrans.StatusIssue == Deducted) and to achieve that, I got the enum values for these fields and wrote it as((InventTrans.StatusReceipt == 1) || (InventTrans.StatusIssue == 2)) in the value column of the range field. Note that the range can now be applied to any field but make sure the data source is names as it is, i.e. InventTrans instead of InventTrans_1.




Bonus:  to do it in X++:

itemQBR.value(strFmt('(%1.%2 LIKE "%3") || (%4.%5 LIKE "%6") || (%7.%8 LIKE "%9")',
                                                                tableStr(GWCustomerItems),
                                                                fieldStr(GWCustomerItems, ItemId),
                                                                SysQuery::valueLike(FilterItems.text()),
                                                                tableStr(GWCustomerItems),
                                                                fieldStr(GWCustomerItems, ShortCode),
                                                                SysQuery::valueLike(FilterItems.text()),
                                                                tableStr(GWCustomerItems),
                                                                fieldStr(GWCustomerItems, ProductName),
                                                                SysQuery::valueLike(FilterItems.text())));

Notice the use of tableStr and fieldStr methods – these ensure that if the table or field names change then you will see the error at compile time rather than noticing errors after it has been deployed into a live environment J

It’s also useful to know that if you have a field like ItemId in the InventTable that you need to filter on you can pass a string that is longer that the ItemId length – this is something that you cannot do when writing a select statement.

Wednesday, February 15, 2017

Catch any type exception

For debugging different types of CLR exception, it took me ages to find the following code, but this helps in finding what kind of exception could be giving the problem (taken from http://sebastienayotte.com/dev/catching-exceptions-microsoft-dynamics-ax-2012/ and saved for future use. All credit goes to the original dev)

Catching Any Type of Exceptions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
System.Exception exception;
 
try
{
    System.Int16::Parse('abcd');
 
    throw Exception::Error;
}
catch
{
    error('Caught an exception');
 
    error(con2Str(xSession::xppCallStack()));
 
    exception = CLRInterop::getLastException();
 
    while (exception)
    {
        error(CLRInterop::getAnyTypeForObject(exception.ToString()));
 
        exception = exception.get_InnerException();
    }
}