Building a Simple Report–Precision Design

In this post, we will see how we can build a report using precision design. A precision design is like a pre-printed format where the placing of report controls, the design and the spacing matters a lot.

A precision design is the standard SSRS report designer following the same principles, rules and requirements as are found in a SQL Server Business Intelligence Studio SSRS designer.

We will again use the same example of printing Customer Id, Customer name and Balance but this time instead of creating an Auto Design we will use Precision Design.

I will also show how we can use some inbuilt parameters to display some generic information like page number, execution date and time etc.

Here we will use the same AOT query created in previous example Build and Deploy Simple Report–Queries: SKL_SampleCustomer

Create the Required Dataset

  • Open the previously created Report Model

image_thumb26

  • Right click on report model, select Add –> Report. Name the report SKL_SampleReportPrecision
  • Set the report title to “Customer balance”

image

  • Now in the report, go to the Datasets section and create new Dataset using the name Customer
  • In the query property, click the button image_thumb6
  • This opens up the query selection box to select a Microsoft Dynamics AX Query
  • From the list select “SKL_SampleCustomer” and click Next
  • image_thumb20

  • Here you can select required fields. Either you can select all fields or a subset
  • Expand All Fields nodes under the CustTable node to select “AccountNum”
  • Expand Node “All Display Methods” and select “name” and “openBalanceMST”
  • Click “Ok”
  • Now Right click on the designs node, select Add and then “Precision Design”. This creates a new Precision Design and name it as PrecisionReport

image

  • Now right click on new Design and select “Edit Using Designer”

image

  • This opens up the SSRS Designer (same as standard SSRS)
  • You can see the standard Report Item tool bar from where you can drag and drop the controls onto the designer surface

image

  • Now from the controls tool bar, drag and drop the Table control onto the Report Designer
  • Select the Tablix and then set the DataSetName property = “Customer”

image

  • Now let us specify headers, Select one text box in the header section and right click, then select “Expression…”

image

  • In the expression editor, you can see lot of sections for Variables, Parameters, Fields, Datasets etc.
  • Here write the following in the space “Set expression for: Value” –  =Labels!@SYS316441
  • This displays the header text using the labels in AX. This label is “Customer”

image

  • Now again specify the values in Second and third text boxes in header row
  • 2nd Column Header(Name) : =Labels!@SYS117778
  • 3rd Column Header (Amount): =Labels!@SYS62867

Specifying the data for the table

  • Now in the data row, move the mouse to first text box and you should see a button on the right side that looks as shown below

image

  • Click the button and it displays the list of fields from the dataset, select required fields

image

  • Alternatively, you can right and use “Expression…” box to specify the data fields. The expression box looks as shown below:

image

Now that the data is ready, we will go ahead and change the look and feel of the report

Formatting the table

You can specify the lots of formats using the properties windows like Background color, Font type color etc. You can also use the formatting tool bar above to format the data

image

Go ahead and specify the borders for the table for each row. Then change the background of the Header row. Make the text in the header row as center aligned and make the font as bold

Select the table rows one by one and change the font to “Segoe UI” and Font Size to “8pt”. Now your table looks as shown below:

image

Now we will go ahead and a Page Header and Page Footer. In Page Header, we will add Report name, Report Title and Execution Date and Time. In the Page Footer, we will add the Page Numbers in the format (Page of Total Pages)

To enable Page Header and Footer, in the Report menu select “Add Page Header” and “Add Page Footer” options

image

image

Now drag three text boxes from tool box and drop onto the Page Header area. Place two text boxes on the left hand corner and one on the right hand corner as shown below. Drag and drop one text box in the center of the Page footer as shown below.

image

Select the first text box, Open the expression box and in the Category section, select “Built-in Fields. Now double click on “ReportName” field and it should add the report name to value section

image

In the same way select “ExecutionTime” in third text box. For report title, Type in “Customer balances” in the second text box

In the footer section, select the 4th text box and type the expression ‘=Globals!PageNumber & ” of ” & Globals!TotalPages’

Apply formatting as required. Now you should see the design as follows

image

Now close the designer, add the report back to AOT (along with the model) and deploy the report from within AOT.

Create a new menu item

Go to AOT –> Menu Items –> Output, Right click and select “New Menu Item”. Set following properties

image

Now run the report and the report will be seen as shown below:

image

Building a simple report – Using Report Data Provider

In my previous post, I explained how we can build a simple report using just the AOT queries. Now what if we have some logic that needs to be implemented and cannot be achieved using AOT queries?

This is where Report Data Providers plays a significant roles. Let us take the same example of displaying the Customer Id, Name and Balance that was used in post “Build and Deploy Simple Report–Queries”.

We can have this report using Report Data Providers as well. For this, we will keep the query and create three more artifacts, RDP, Report and a new Output menu item.

First we create a Report Data Provider class named “SKL_SampleReportDP”. Do the following:

To create an RDP for a report, we also need a temporary table (if it is Base Provider) or a permanent table (if it is pre process provider).

For this sample, we will use CustTmpAccountSum table that is present in base product.

Here are the class methods

/// <summary>

/// The <c>SKL_SampleReportDP</c> class is the report data provider class for the

/// SKL_SampleSimpleReportQuery report.

/// </summary>

/// <remarks>

/// This is a sample class. Author: Sumit Loya

/// </remarks>

[ SRSReportQueryAttribute (querystr(SKL_SampleCustomer))]

class SKL_SampleReportDP extends SRSReportDataProviderBase

{

    CustTmpAccountSum   tmpAccountSum;

}

 

The class declaration contains one attribute “SRSReportQueryAttribute”. This attribute specifies the query that will be used for this report. In case no query is required, this attribute can be removed.

There is one other attribute that can be specified on the RDP class and that is SRSReportParameterAttribute. This attribute defines the contract class that will be used to display report parameters.

processReport method

The processReport method is the entry point for calculating the report data for dataset. Here is the method for our sample class

[SysEntryPointAttribute(false)]

public void processReport()

{

    this.insertTmpAccountSum();

}

 

insertTmpAccountSum method

This is a private method that uses the report query to insert data into the temporary table

/// <summary>

/// This method processes the report query and inserts data into the CustTmpAccountSum temporary table

/// </summary>

private void insertTmpAccountSum()

{

    QueryRun            queryRun = new QueryRun(this.parmQuery());

    CustTable           custTable;

   

    while (queryRun.next())

    {

        custTable = queryRun.get(tableNum(custTable));

       

        tmpAccountSum.AccountNum    = custTable.AccountNum;

        tmpAccountSum.Txt           = custTable.name();

        tmpAccountSum.Balance01     = custTable.openBalanceMST();

        tmpAccountSum.insert();

    }

}

 

getCustTmpAccountSum method

This method is mandatory as it returns the table buffer that contains the processed report data. The Dataset uses this buffer to bind the table to the dataset.

/// <summary>

/// This method returns the table buffer that contains processed data

/// </summary>

[SRSReportDataSetAttribute(tableStr(CustTmpAccountSum))]

public CustTmpAccountSum getCustTmpAccountSum()

{

    select * from tmpAccountSum;

 

    return tmpAccountSum;

}

 

After creating the class, go ahead and add a new report the existing report model.

  • Open the previously created Report Model

image

  • Right click on report model, select Add –> Report. Name the report SKL_SampleReportDP
  • Now in the report, go to the Datasets section and create new Dataset using the name CustomerDP
  • The parameters for the new Dataset should be as shown below. The Data Source Type is “Report Data Provider”

image

  • In the query property, click the button image_thumb6
  • This opens a box to select a data provider class
  • Select the class we created before, SKL_SampleReportDP and click “Next”

image

  • In the next tab, Deselect all fields and just select “AccountNum, Balance01 and Txt” fields
  • Click Ok

image

  • This is how the data set looks like

image

  • Now create a new Auto Design as before and name it as CustDP, Select a Layout Template for the report design in Parameters window
  • Now right click on newly created design select “Add” and “Table”
    • Set following properties
      • Name – CustDP
      • Dataset – CustomerDP
      • Style Template – TableStyleAlternatingRowsTemplate
  • You will also notice that the fields are included automatically from Dataset to the “Data” node of the table

image

  • Now right click on the report model and select option “Add SKL_SampleReportProject to AOT”
  • Once the report is created back to AOT, go to AX, find the report in AOT –> SSRS Reports –> Reports, right click and deploy using “Deploy Element” option
  • Once the deployment is successful, create an output type menu item for the report
  • Go to AOT –> Menu Items –> Output, Right click and select “New Menu Item”. Set following properties

image

Now using menu item open and run report. You will notice the same dialog

image

The report looks like as shown below:

image

Build and Deploy Simple Report–Queries

In this post, I will explain about creating a simple AX SSRS Report using the queries from AX AOT. This is what you need to do:

  • Login to AX and open the development workspace
  • Go to AOT –> Queries, right click and select “New Query”
  • Rename the query to “SKL_SampleCustomer”
  • Go to Query’s data source node and right click and select “New Data Source”
  • Rename the data source to “CustTable” and set property table to “CustTable”
  • Now go to the “Fields” node of this query and set property: Dynamic to “Yes”
  • The query looks as shown below

image

  • Save the query
  • Now open visual studio and create a new reporting project by name SKL_SampleReportProject
  • On the reporting model, right click, select “Add” and then Report
  • This will add new report to the project

image

  • Name this report as “SKL_SampleSimpleReportQuery”
  • In the report, Right click on the Dataset node and select “Add Dataset”

image

  • Name the data set as customer
  • On the properties window, ensure following properties are set by default

image

  • In the query property, click the button image
  • This opens up the query selection box to select a Microsoft Dynamics AX Query
  • From the list select “SKL_SampleCustomer” and click Next

image

  • Here you can select required fields. Either you can select all fields or a subset
  • Expand All Fields nodes under the CustTable node to select “AccountNum”
  • Expand Node “All Display Methods” and select “name” and “openBalanceMST”
  • Click “Ok”

image

image

image

  • This will generate the required fields for the dataset

image

  • Now Right click on the designs node, select Add and then “Auto Design”. This creates a new Auto Design and name it as Report

image

  • Select a layout template say “ReportLayoutStyleTemplate”

image

  • Now right click on newly created design select “Add” and “Table”

image

  • Set following properties
    • Name – Cust
    • Dataset – Customer
    • Style Template – TableStyleAlternatingRowsTemplate
  • You will also notice that the fields are included automatically from Dataset to the “Data” node of the table

image

  • Click on Preview once to view the report

image

Note: It may not be possible to preview all reports from VS, especially when there are some internal parameters etc.

  • Now right click on the report model and select option “Add SKL_SampleReportProject to AOT”

image

  • Once the report is added, go to AX, find the report in AOT –> SSRS Reports –> Reports, right click and deploy using “Deploy Element” option
  • Once the deployment is successful, create an output type menu item for the report
  • Go to AOT –> Menu Items –> Output, Right click and select “New Menu Item”. Set following properties

image

  • Now using menu item open and run report.

When you open the menu item, a dialog is automatically made and shown and you will notice that there is also a select button

image

This happens as we had kept the Dynamics Filter property on Dataset in report to “True”. Hence the Reporting framework adds a select button.

The displaying of dialog box can be handled as well. We will cover this topic when we learn about controller classes.

The report will look like this:

image

Note: The name has been intentionally removed from image

Hope this helps you in building your first simple report.

Remove a Financial Dimension Value

Here is a job that can help you remove or blank out a financial dimension.

Note the Dimensions before executing this job

image

Job

static void sgxRemoveWorkerDimension(Args _args)

{

    /*

     * We will Remove a worker dimension in this example

    */

    CustTable                       custTable = CustTable::find(‘CUS-00004’); //Customer Record containing Financial Dimension

    DimensionSHA1Hash               hash; //To store the calculated hash for DimensionAttributeValueSet

    DimensionAttribute              dimAttr; // Contains the financial dimensions records

    DimensionAttributeValue         dimAttrValue; // Contains used financial dimension values

    DimensionAttributeValueSet      dimAttrValueSet; //Contains default dimension records

    DimensionAttributeValueSetItem  dimAttrValueSetItem; //Contains individual records for default dimensions

    DimensionAttributeSetItem       dimAttrSetItem; // Contains the number of dimensions active for a account structure ledger

 

    HashKey     valueKeyHashArray[]; //To store the has key of dimension in question

    Map         dimAttrRecId, dimAttrStr; //To store the dimension attribute recid and dimension attribute value display value

    Set         dimAttrValueRecId;

    SetEnumerator   setEnum;

    int dimAttrCount, i;

 

   

    //Initialize the map to store the backing entity types

    dimAttrRecId = new Map(Types::Int64, Types::Integer);

    dimAttrValueRecId = new Set(Types::Int64);

    dimAttrStr = new Map(Types::Int64, Types::String);

 

    //Find all the active dimensions for current ledger except main account and store there

    //backing entity type in the map

    while select RecId from dimAttr

            order by Name

            where dimAttr.Type != DimensionAttributeType::MainAccount

            join RecId from dimAttrSetItem

                where dimAttrSetItem.DimensionAttribute == dimAttr.RecId &&

                      dimAttrSetItem.DimensionAttributeSet == DimensionCache::getDimensionAttributeSetForLedger()

    {

        dimAttrCount++;

        dimAttrRecId.insert(dimAttr.RecId, dimAttrCount);

    }

 

    //initialize hash key array to null

    for (i = 1; i<= dimAttrCount; i++)

        valueKeyHashArray[i] = emptyGuid();

 

    //Get individual dimension attribute records and display values except worker dimension

    //Store them in sets

    while select DisplayValue, DimensionAttributeValue from dimAttrValueSetItem

            where dimAttrValueSetItem.DimensionAttributeValueSet == custTable.DefaultDimension

            join DimensionAttribute, HashKey from dimAttrValue

                where dimAttrValue.RecId == dimAttrValueSetItem.DimensionAttributeValue

                join RecId from dimAttr

                    where dimAttr.RecId == dimAttrValue.DimensionAttribute

                       && dimAttr.BackingEntityType != tableNum(DimAttributeHcmWorker) //As we ignore worker dimension, its hash key remains blank

    {

        dimAttrValueRecId.add(dimAttrValueSetItem.DimensionAttributeValue);

        dimAttrStr.insert(dimAttrValueSetItem.DimensionAttributeValue, dimAttrValueSetItem.DisplayValue);

        valueKeyHashArray[dimAttrRecId.lookup(dimAttrValue.DimensionAttribute)] = dimAttrValue.HashKey;

    }

 

    //Calculate the hash for the current values

    hash = DimensionAttributeValueSetStorage::getHashFromArray(valueKeyHashArray, dimAttrCount);

 

    //Null hash indicates no values exist, which may occur if the user entered an invalid value for one dimension attribute

    if (hash == conNull())

    {

        throw error(“Wrong value for Dimensions”);

    }

 

    // Search for existing value set

    dimAttrValueSet = DimensionAttributeValueSet::findByHash(hash);

 

    // This value set does not exist, so it must be persisted

    if (!dimAttrValueSet)

    {

        ttsbegin;

        // Insert the value set with appropriate hash

        dimAttrValueSet.Hash = hash;

        dimAttrValueSet.insert();

 

        // Insert only specified set items use this

        setEnum = dimAttrValueRecId.getEnumerator();

 

        while (setEnum.moveNext())

        {

            dimAttrValueSetItem.clear();

            dimAttrValueSetItem.DimensionAttributeValueSet = dimAttrValueSet.RecId;

            dimAttrValueSetItem.DimensionAttributeValue = setEnum.current();

            dimAttrValueSetItem.DisplayValue = dimAttrStr.lookup(setEnum.current());

            dimAttrValueSetItem.insert();

        }

        ttscommit;

    }

   

    ttsBegin;

    custTable.selectForUpdate(true);

    custTable.DefaultDimension = dimAttrValueSet.RecId;

    custTable.doUpdate();

    ttsCommit;

}

 

Result After Job Run

image

Dynamics AX Vrooms into F1

Friends, Dynamics AX has been adopted by Lotus F1 team to manage their every aspect of the business.

In turn the Microsoft Dynamics Logo will be appearing on the Lotus Race Car for everyone to see.

Way to go Team Dynamics Vrooom Vroooom.

Read the entire news here.

image

Report Design and Controls

Finally I have sometime on hand that I can use to continue my posts on Reporting framework. I have not been able to update my blog due to various reasons but lets get started again.

In my previous posts I had covered about reporting framework terminologies and reporting project. In this post, let us go through the types of designs available for reports and different controls that are available for a report. Together all these elements form Report Model Elements

The first and foremost model element is the “Report” element itself

Report: The report element represents a report definition. A report definition contains a collection of elements such as datasets, parameters, images, and report designs.

The elements that define a report are located under the node for the report in a model. The report in turn contains Report Designs and Report Controls. A report element can be identified by following symbol:  image

Report Designs

Dynamics AX SSRS reports contains two types of report designs

  • Precision Design
  • Auto Design

Precision Design

A precision design is a report design that is created by using SQL Report Designer (Standard SSRS Report Designer). Precision designs are useful when a very precise layout is required.

These reports are like pre-printed formats where we know the format of the report while designing them.  You can identify a precision design by the following symbol: image

Auto Design

An auto design is a report design that is automatically generated based on the report data. An auto design is created by using drag-and-drop actions, and selecting elements by using Model Editor.

You cannot have specific formats in the Auto Design. This design is useful mostly for tabular and matrix type reports with simple groupings and sorting. You can identify a precision design by the following symbol: image

Report Controls

The report element can have following report controls or elements

  • Dataset
  • Data Region
  • Parameter
  • Filter
  • Grouping
  • Sorting
  • Data Method

Dataset

A dataset identifies data that is displayed in a report. Every report must have one or more datasets. Default data sources that are available for Datasets are “Dynamics AX” and “DynamicsAXOLAP”. The data sets can have data fetched by using anyone of the following options:

  • A query (Dynamics AX AOT query or an OLAP MDX Expression)
  • Report Data Provider
  • Business Logic (C# Business Logic with the reporting project only)
  • AX Enum Provider (Enum values)

A dataset can be identified by image symbol.

Data Region

A data region is an area in a report that displays data. Data can be displayed in following formats

  • Table – Data displayed in columns and rows. Symbol: image
  • Matrix – Data displayed in matrix format. Symbol: image
  • List – Data displayed in list format. Symbol: image
  • Pie Or Doughnut Chart – A chart type report. Symbol: image
  • XY Chart – A chart type reports (Bars, Columns, Lines on XY axis). Symbol: image

Please note that all  these data regions are available in Auto Design report only. The Precision Design has its own standard SSRS report controls.

Parameter

A parameter lets you parameterize data for a report. With the help of parameters, you can filter the data to the required values.

Parameters can be identified by following symbol: image

Filter

A filter is used to filter or restrict the data that is displayed in a report.The Dynamics Filter property on the dataset determines how filters are created for a report. If the Dynamics Filters property on the dataset is set to True, the end user of the report will identify the ranges when they view the report. To manually define the set ranges to filter data on a report, verify the Dynamics Filters property on the dataset is set to False and create your own filters.

Filters can be identified by following symbol: image. Again these filters are available only for Auto Design. The Precision Design has its own way of defining filters

Grouping

A grouping lets you organize data that displays in a report by grouping fields. For Auto Design, you can see a node called grouping for Table or Matrix type data regions. Groupings in Precision Design follow the same procedure that is used in Standard SSRS Reports.

Groupings can be identified by symbol: image

Sorting

A sort lets you control the order in which data displays in a report. For example, you can sort alphabetically by field in ascending or descending order.

Sorting can be identified by symbol: image

Data Method

A data method contains code to retrieve and process data for a report. The code for a data method is written in C# or Visual Basic, depending on which project template is used.

Data Method are designated by following symbol: image

Layout Templates

A layout template specifies the styles that are applied to the header, footer, and body of a report. One layout template can be applied to many reports. Layout Templates are created in a reporting project and are separate from Report Controls.

There are default layout templates available but we can define our own custom templates to suit the needs of the customers.

Layout Templates are identified by symbol: image

Style Templates

A style template specifies the styles that are applied to a data region. When you create a style template, you will notice that there are several types of templates that you can create based on the data region type. A style template can be applied to more than one data region in a report, and it can be applied to data regions in more than one report.

Following are the style templates that you can create (1 per data region type)

  • Table – Symbol: image
  • Matrix – Symbol: image
  • List – Symbol: image
  • Pie Or Doughnut Chart – Symbol: image
  • XY Chart – Symbol: image

Report Data Sources

A data source is a source of data for a report dataset. You can use the predefined data source, which connects to the Microsoft Dynamics AX application database. Or, you can define your own data sources. System by default provides data sources for “Dynamics AX” and “DynamicsAXOLAP”.

Data Sources have symbol image associated with them.

This concludes the report designs and controls.

Create Project Tool for Developers [AX 2012]

A small tool that I upgraded from AX 2009 to AX 2012 and added a few more options is available for download now.

This tool can help create Shared / Private projects for developers quickly and the same order as in AOT.

Creating project elements in proper order is something that many developers find a bit ‘tedious’ job. Now include this tool in your development environment and quickly create projects Smile. I have added this tool in “Tools” menu in development workspace.

Download the tool from here

Here is a sample screen of the tool.

image

 

image

image