Month: April 2015

AX 2012: Create SSRS Column Chart Report

Posted on Updated on

Untitled

Purpose:

The purpose of this document is to demonstrate how to develop SSRS column chart report in Dynamics AX 2012.

Prerequisites:

  1. Visual Studio 2010
  2. Visual Studio tools.
  3. Reporting extension.
  4. Report Builder.
  5. Should be well-versed in Report Programming Model.

Business Requirement:

Create a column chart report to show top products sold in the year 2012.

Project Overview:

Untitled

Data Analysis:

Untitled

Use the above SQL query result to validate the report which shows the product IDs sorted on the quantity sold in descending order.

Development Steps:

1. Create an RDP class MAKTopProductsSoldDP. Give the definition of processReport method as follows:

[SysEntryPointAttribute]
public void processReport()
{
    MAKSalesTable   makSalesTable;

    while select ProductSold, sum(SalesQty) from makSalesTable
        group by makSalesTable.ProductSold
            order by makSalesTable.SalesQty desc
    {
        this.setMAKSalesTableTmp(makSalesTable);
    }
}

2. Create a new method setMAKSalesTableTmp and give the following definition:

private void setMAKSalesTableTmp(MAKSalesTable _makSalesTable)
{
    makSalesTableTmp.clear();

    makSalesTableTmp.ProductSold = _makSalesTable.ProductSold;
    makSalesTableTmp.SalesQty = _makSalesTable.SalesQty;

    makSalesTableTmp.insert();
}

3. Create a new method getMAKSalesTableTmp and give the following definition:

[SRSReportDataSetAttribute(tableStr(MAKSalesTableTmp))]
public MAKSalesTableTmp getMAKSalesTableTmp()
{
    select makSalesTableTmp
        order by SalesQty desc;
    return makSalesTableTmp;
}

4. Open Visual Studio 2010 and create a new project of type Report Model, MAKTopProductsSold choosing Microsoft Dynamics AX from installed templates.

Untitled

5. Add new Report MAKTopProductsSold to the Project node in the Solution Explorer.
6. Add new Precision Design to the Designs node of the report.
7. Right click the precision design and click Edit Using Designer.
8. Drag Chart from the Toolbox.
9. Set Chart axes properties appropriately to show Products on the X-Axis and Quantity on the Y-Axis.

Untitled

10. Improve formatting of the chart using some professional intellect 🙂
11. Deploy the report to the Report Server using Microsoft Dynamics AX 2012 Management Shell.

Untitled

12. Create a new controller class MAKTopProductsSoldController and give the following definition for the main method:

static void main(Args _args)
{
    MAKTopProductsSoldController    controller;

    controller = new MAKTopProductsSoldController();
    controller.parmReportName(ssrsReportStr(MAKTopProductsSold, PrecisionDesign));
    controller.parmArgs(_args);
    controller.parmShowDialog(false);
    controller.startOperation();
}

13. Create a new output menu item MAKTopProductsSold to point it to the controller class. Sets its properties as shown below:

Untitled

14. Run the report using the output menu item. Notice that the report dialog has been suppressed by the controller.
15. You should be able to see the report in action 🙂

AX 2012: Mastering Batch Framework

Posted on Updated on

Master the Batch Framework in Dynamics AX 2012 by going through the following topics in sequence. The initial topics discuss the basics followed by advanced and complex concepts of the Batch Framework. All the posts will be based on the SysOperation framework which is recommended over the depreciated RunBase framework to develop customized batch jobs.

Following are the topics which are listed in the order of their complexity:

1. Create a simple batch job.

This post describes how to develop a fully functional customized batch job with the following minimum development artifacts:

  • Service operation class

2. Add fields to batch job dialog.

This post builds on the previous topic and describes how to use data contracts to add custom fields to the batch job dialog to control the service operation. It uses the following development artifacts:

  • Service operation class
  • Data contract class

3. Add lookup to batch job dialog.

This post builds on the previous topic and describes how to develop custom UI builder class extending SysOperationAutomaticUIBuilder base class to add lookups and custom validations to batch job dialog. It uses the following development artifacts:

  • Service operation class
  • Data contract class
  • UI Builder class

4. Customize controller for batch job.

This post builds on the previous topic and describes how to develop custom controller class extending SysOperationServiceController base class to have more control over execution modes of the service operation as well as initializing dialog fields with default values. It uses the following development artifacts:

  • Service operation class
  • Data contract class
  • UI Builder class
  • Controller class

AX 2012: Customize Controller for Batch Job

Posted on Updated on

The purpose of this document is to demonstrate what power we can leverage by customizing the controller for our batch job. For simplicity, we’ll explore how we can set batch dialog fields with default values by extending SysOperationServiceController class.

Prerequisites:

It is highly recommended to go through the following posts to get a better understanding of what we have done so far in the Batch Framework series.

1. Create a simple batch job.
2. Add fields to batch job dialog.
3. Add lookup to batch job dialog.

Business Requirement:

To set batch dialog fields with default values.

Project Overview:

Untitled

Development Steps:

1. Create a new class MAKSalesTableServiceController extending SysOperationServiceController base class.

class MAKSalesTableServiceController extends SysOperationServiceController
{
}

2. Override the new method and give the following definition:

public void new()
{
    super();

    this.parmClassName(classStr(MAKSalesTableService));
    this.parmMethodName(methodStr(MAKSalesTableService, processRecords));
}

3. Create a new method main and give the following definition. This is where the magic happens. The controller is used to get reference to data contract object which is then modified to initialize data members, by calling their parm methods, with default values.

static void main(Args _args)
{
    MAKSalesTableServiceController  controller;
    MAKSalesTableContract           dataContract;

    controller = new MAKSalesTableServiceController();

    // Run operation synchronously, asynchronously or in batch
    // Async execution requires service to be published
    // in the AxClient service group
    controller.parmExecutionMode(SysOperationExecutionMode::ReliableAsynchronous);

    // Get the contract from the controller and initialize it default values
    dataContract = controller.getDataContractObject();
    dataContract.parmFromDate(systemDateGet());
    dataContract.parmToDate(systemDateGet());
    dataContract.parmSalesChannel("Direct");

    // call the operation. The controller will handle execution mode
    controller.startOperation();
}

4. Modify Menu Items > Action > MAKSalesTableService to point to MAKSalesTableServiceController class just created.

Untitled

5. Compile and generate incremental CIL.
6. Click Tools > Caches > Refresh elements to refresh the AOD cache to reflect changes on the batch dialog.
7. Click Menu Items > Action > MAKSalesTableService to run the batch job.
8. You should now be getting batch dialog fields initialized with default values 🙂

Untitled

AX 2012: Add Lookup to Batch Job Dialog

Posted on Updated on

Prerequisites:

1. Create a simple batch job.
2. Add fields to batch job dialog.

Business Requirement:

To have a lookup on the batch job dialog to filter records to be processed based on the user selected value of sales channel field on the dialog.

Project Overview:

Untitled

We’ll be adding a new UI Builder class MAKSalesTableUIBuilder and link it with the MAKSalesTableContract class to add lookup on the batch dialog. It is highly recommended to read the prerequisites first before proceeding any further to have better understanding of the topic.

Development steps:

1. Add salesChannel variable to the class declaration of MAKSalesTableContract class to store sales channel value:

[DataContractAttribute]
class MAKSalesTableContract
{
    TransDate           fromDate;
    TransDate           toDate;
    MAKSalesChannel     salesChannel;
}

2. Add parm method for sales channel variable to designate it as a data member of the contract class:

[
    DataMemberAttribute,
    SysOperationLabelAttribute(literalStr("Sales channel")),
    SysOperationHelpTextAttribute(literalStr("Pick sales channel")),
    SysOperationDisplayOrderAttribute('3')
]
public MAKSalesChannel parmSalesChannel(MAKSalesChannel _salesChannel = salesChannel)
{
    salesChannel = _salesChannel;

    return salesChannel;
}

3. Compile and generate incremental CIL.
4. Click Tools > Caches > Refresh elements to refresh the AOD cache to reflect changes on the batch dialog.
5. You should be able to see newly added Sales channel field on the batch dialog but without a lookup.

Untitled

6. Create a new class MAKSalesTableUIBuilder which extends SysOperationAutomaticUIBuilder base class:

class MAKSalesTableUIBuilder extends SysOperationAutomaticUIBuilder
{
    #define.lookupAlways(2)

    DialogField     fromDateField;
    DialogField     toDateField;
    DialogField     salesChannelField;
}

7. Override the postBuild method of the base class to get the references to dialog field controls after creation:

public void postBuild()
{
    super();

    //Get references to dialog controls after creation
    fromDateField = this.bindInfo().getDialogField(
        this.dataContractObject(), methodStr(MAKSalesTableContract, parmFromDate));
    
    toDateField = this.bindInfo().getDialogField(
        this.dataContractObject(), methodStr(MAKSalesTableContract, parmToDate));
    
    salesChannelField = this.bindInfo().getDialogField(
        this.dataContractObject(), methodStr(MAKSalesTableContract, parmSalesChannel));

    //Change text field metadata to add lookup
    salesChannelField.lookupButton(#lookupAlways);
}

8. Override the postRun method of the base class to register the custom lookup method salesChannelFieldLookup with the form control event lookup:

public void postRun()
{
    super();

    //Register overrides for form control events
    salesChannelField.registerOverrideMethod(
        methodstr(FormStringControl, lookup),
        methodstr(MAKSalesTableUIBuilder, salesChannelFieldLookup),
        this);
}

9. Give the following implementation for the custom lookup method salesChannelFieldLookup:

public void salesChannelFieldLookup(FormStringControl _control)
{
    Query                   query;
    QueryBuildDataSource    qbdsMAKSalesTable;
    SysTableLookup          sysTableLookup;

    query = new Query();
    qbdsMAKSalesTable = query.addDataSource(tableNum(MAKSalesTable));
    qbdsMAKSalesTable.fields().clearFieldList();
    qbdsMAKSalesTable.fields().addField(fieldNum(MAKSalesTable, SalesChannel));
    qbdsMAKSalesTable.addGroupByField(fieldNum(MAKSalesTable, SalesChannel));

    sysTableLookup = SysTableLookup::newParameters(tableNum(MAKSalesTable), _control);
    sysTableLookup.addLookupfield(fieldNum(MAKSalesTable, SalesChannel));
    sysTableLookup.parmQuery(query);
    sysTableLookup.performFormLookup();
}

10. Lastly, modify the class declaration of MAKSalesTableContract class to link it with the MAKSalesTableUIBuilder class we just created by decorating it with the SysOperationContractProcessingAttribute:

[
    DataContractAttribute,
    SysOperationContractProcessingAttribute(classStr(MAKSalesTableUIBuilder))
]
class MAKSalesTableContract
{
    TransDate           fromDate;
    TransDate           toDate;
    MAKSalesChannel     salesChannel;
}

11. Compile and generate incremental CIL.
12. Click Tools > Caches > Refresh elements to refresh the AOD cache to reflect changes on the batch dialog.
13. Click on the menu item MAKSalesTableService to run the batch job dialog.
14. You should now be getting a lookup generated for the Sales channel field on the batch dialog 🙂

Untitled

Next:

Next in the series: Customize controller for batch job.

AX 2012: Add Fields to Batch Job Dialog

Posted on Updated on

Prerequisites:

1. Create a simple batch job.

Requirement:

To add custom fields to batch job dialog to choose a date range to process only those records falling in that date range.

Project overview:

Untitled

As you can see in the picture, a data contract class MAKSalesTableContract has been added to the project to achieve the goal. We’ll be adding from date and to date fields on the batch dialog to capture the date range.

Development steps:

1. Create a new data contract class MAKSalesTableContract with the following class declaration:

[DataContractAttribute]
class MAKSalesTableContract
{
    TransDate   fromDate;
    TransDate   toDate;
}

2. Create a new method parmFromDate with the following definition:

[
    DataMemberAttribute,
    SysOperationLabelAttribute(literalStr("From Date")),
    SysOperationHelpTextAttribute(literalStr("Pick a valid begin date")),
    SysOperationDisplayOrderAttribute('1')
]
public TransDate parmFromDate(TransDate _fromDate = fromDate)
{
    fromDate = _fromDate;

    return fromDate;
}

3. Create a new method parmToDate with the following definition:

[
    DataMemberAttribute,
    SysOperationLabelAttribute(literalStr("To Date")),
    SysOperationHelpTextAttribute(literalStr("Pick a valid end date")),
    SysOperationDisplayOrderAttribute('2')
]
public TransDate parmToDate(TransDate _toDate = toDate)
{
    toDate = _toDate;

    return toDate;
}

4. Update the MAKSalesTableService.processRecords method to the following definition:

[SysEntryPointAttribute(false)]
public void processRecords(MAKSalesTableContract _contract)
{
    MAKSalesTable   makSalesTable;
    int             counter = 0;

    //Determines the runtime
    if (xSession::isCLRSession())
    {
        info('Running in a CLR session.');
    }
    else
    {
        info('Running in an interpreter session.');

        //Determines the tier
        if (isRunningOnServer())
        {
            info('Running on the AOS.');
        }
        else
        {
            info('Running on the Client.');
        }
    }

    //Actual operation performed
    while select forUpdate makSalesTable
        where makSalesTable.TransDate >= _contract.parmFromDate()
            && makSalesTable.TransDate <= _contract.parmToDate()
    {
        ttsBegin;
        makSalesTable.Processed = NoYes::Yes;
        makSalesTable.update();
        ttsCommit;

        counter++;
    }

    info(strFmt("Successfully processed %1 records.", counter));
}

This is where the magic happens. Note that method now takes an input parameter of type MAKSalesTableContract class. Then it filters the records to be processed in the while loop by adding ranges to the MAKSalesTable.TransDate field, using the values given by user on the batch dialog for From Date and To Date.

5. Compile and generate incremental IL.
6. Click on Menu Items > Action > MAKSalesTableService to run the batch job.
7. You should now be having 2 fields added to the batch dialog:

Untitled

Next:

Next in the series: Add lookup to batch job dialog.

AX 2012: Switch TFS branch

Posted on Updated on

Please follow the instructions below to switch the TFS branch of the Dynamics AX development environment.

  1. Add user to Administrators group using an admin account.
  2. Add user to AX Debugging users group using an admin account.
  3. Create new login for the user to SQL Server > Security node.
  4. Disconnect AX from TFS. Disable version control.
  5. Delete existing TFS workspaces from Visual Studio.
  6. Delete existing TFS repository folders on the file system.
  7. Create TFS repository folder preferrably in C:\TFS\…
  8. Create new client configuration for CUS layer.
  9. Open AX.
  10. Configure TFS for AX and enable version control.
  11. Open VS.
  12. Connect to TFS project.
  13. There should be single TFS workspace coming up in the workspaces dropdown.
  14. Check TFS branch mapping.
  15. Force sync AX.

AX 2012: Create a Simple Batch Job

Posted on Updated on

In this post we’ll learn how to create a very basic custom Batch job using SysOperation framework. We’ll use the base controller class SysOperationServiceController and develop a custom service operation class to achieve the goal.

Requirement:

To create a Batch job to mark all the records as processed in a custom table MAKSalesTable.

Project overview:

Untitled

The project shows how simple yet powerful the SysOperation framework is for developing custom batch jobs as opposed to RunBase framework since the minimum development needed to create a fully functional batch job is to create a custom service operation class defining a single method giving the implementation for the batch operation to be performed.

Development steps:

1. Create a service operation class MAKSalesTableService having the following class declaration:

class MAKSalesTableService
{
}

2. Create a new method in the class giving a suitable name like processRecords having the following definition:

[SysEntryPointAttribute(false)]
public void processRecords()
{
    MAKSalesTable   makSalesTable;
    int             counter = 0;

    //Determines the runtime
    if (xSession::isCLRSession())
    {
        info('Running in a CLR session.');
    }
    else
    {
        info('Running in an interpreter session.');

        //Determines the tier
        if (isRunningOnServer())
        {
            info('Running on the AOS.');
        }
        else
        {
            info('Running on the Client.');
        }
    }

    //Actual operation performed
    while select forUpdate makSalesTable
    {
        ttsBegin;
        makSalesTable.Processed = NoYes::Yes;
        makSalesTable.update();
        ttsCommit;

        counter++;
    }

    info(strFmt("Successfully processed %1 records.", counter));
}

3. Create an action menu item MAKSalesTableService pointing to SysOperationServiceController.

4. Set the parameters of the action menu item to the service operation just created, MAKSalesTableService.processRecords.

Untitled

5. Compile the service operation class and generate incremental IL.

6. Click on the action menu item to run the batch job. Check the Batch processing checkbox to run the job in CLR runtime which is the batch server execution environment.

Untitled

Untitled

7. Click System administration > Inquiries > Batch jobs to view the status of the job. You may also click on the Log button to view the messages written to infolog during the job execution.

Untitled

Untitled

Preconditions:

Before running the batch job, all the records were unprocessed:

Untitled

Post conditions:

After running the batch job, the list page shows that all the records are now marked as processed:

Untitled

Next:

Next in the series: Add fields to batch job dialog.