Tuesday 29 July 2014

Microsoft Dynamics Axapta

Tables in Microsoft Dynamics AX have a number of system-defined methods, such as insertvalidateFieldvalidateWrite. For a list of these methods, see the xRecordsystem class. The xRecord class can be seen as the base class for the Common table. The Common table can be seen as the base table for all tables.
In any table class, the body of each system-defined method contains only a call to super(). When you edit the X++ code in a table method, you override the parent's implementation of that method. Usually the call to super() must remain in the methods that you edit.




A table can extend from or derive from another table. Each table has the SupportInheritance property and the Extends property, which together control table inheritance.
The default for each new table is to implicitly extend from the Common table. The extension from the Common table cannot be set or seen in the Extends property. A variable that is declared of a specific table also implicitly inherits methods from the xRecord class.


Report Data Provider

To define a data contract class


A data contract is an X++ class that has getters, setters and the DataContractAttribute attribute. You create the RDP and data contract classes in the MorphX code editor. For information about how to create an X++ class, see Declaration of Classes.
The following example illustrates the code to declare a data contract class.

[DataContractAttribute]
public class SrsRDPContractSample
{
    AccountNum accountNum;
    CustAccountStatment accountStmt;
    boolean inclTax;
}

A data contract class has methods with the DataMemberAttribute attribute. The name that follows the attribute is the parameter name that displays in Visual Studio when you bind a report data set to the RDP class. Add a method named parmAccountNum in code editor.
The following example illustrates the code for the parmAccountNum method.
[DataMemberAttribute("AccountNum")]
public AccountNum parmAccountNum(AccountNum _accountNum = accountNum)
{
    accountNum = _accountNum;
    return accountNum;
}

Add a method named parmAccountStmt in code editor.
The following example illustrates the code for the parmAccountStmt method.
[DataMemberAttribute("CustAccountStatement")]
public CustAccountStatement parmAccountStmt(CustAccountStatement _accountStmt = accountStmt)
{
    accountStmt = _accountStmt;
    return accountStmt;
}
Add a method named parmInclTax in code editor.
The following example illustrates the code for the parmInclTax method.
[DataMemberAttribute("InclTax")]
public boolean parmInclTax(boolean _inclTax = inclTax)
{
    inclTax = _inclTax;
    return inclTax;
}

To define a report data provider class

An RDP class extends the SRSReportDataProviderBase class. You set the SRSReportParameterAttribute attribute to the data contract you created for the RDP class. The data contract defines the parameters that the report uses. You set the SRSReportQueryAttribute attribute to the query specified in the parmQuery method in the RDP class.
The following example illustrates an RDP class declaration that uses the SrsRDPContractSample data contract class and the Cust query.
[
    SRSReportQueryAttribute('Cust'),
    SRSReportParameterAttribute(classstr(SrsRDPContractSample))
]
public class SrsRdpSampleClass extends SRSReportDataProviderBase
{
    TmpCustTableSample tmpCust;
}

Your code will get parameters from the end user, process business logic to generate data in a table and then return the table to render in the report. You will define a method that returns a table of the data that you process in the RDP class.
A table returned by a method can be a temporary table (InMemory or TempDB) or a regular table. When the data returned is used for reporting only, it is a best practice to use a temporary table.
  • Use an InMemory temporary table if the data set is small, like 1000 records.
  • Use a TempDB temporary table for large data sets to improve performance.
You can have one or more methods return tables.
NoteNote
If the data returned depends on the company context the report is run from, then the tables returned by the RDP class must have the table propertySaveDataPerCompany set to Yes.
The following example illustrates an RDP class method named getTmpCustTable.
[SRSReportDataSetAttribute('TmpCust')]
public TmpCustTableSample getTmpCustTable()
{
    select * from tmpCust;
    return tmpCust;
}

You will provide the report business logic in the processReport method. Override the processReport method to provide business logic for your report.
The following example illustrates how the processReport method computes data and populates the data tables that will be returned to Reporting Services.
public void processReport()
{
    AccountNum              accntNum;
    CustAccountStatement    custAcctStmt;
    boolean                 boolInclTax;
    Query                   query;
    QueryRun                qr;
    QueryBuildDataSource    queryBuildDataSource;
    QueryBuildRange         queryBuildRange;
    CustTable               queryCustTable;

    SrsRdpContractSample    dataContract;

    // Get the query from the runtime using a dynamic query.
    query = this.parmQuery();
        
    // Get the parameters passed from runtime.
    dataContract = this.parmDataContract();
    accntNum = dataContract.parmAccountNum();
    custAcctStmt = dataContract.parmAccountStmt();
    boolInclTax = dataContract.parmInclTax();
        
    // Add parameters to the query.
    queryBuildDataSource = query.dataSourceTable(tablenum(CustTable));
        
        
    if(accntNum)
    {
        queryBuildRange = queryBuildDataSource.findRange(fieldnum(CustTable, AccountNum));
        if (!queryBuildRange)
        {
            queryBuildRange = queryBuildDataSource.addRange(fieldnum(CustTable, AccountNum));
        }
        // If an account number has not been set, then use the parameter value to set it.
        if(!queryBuildRange.value())
            queryBuildRange.value(accntNum);
    }        
        
    if(custAcctStmt)
    {
        queryBuildRange = queryBuildDataSource.findRange(fieldnum(CustTable, AccountStatement));
        if (!queryBuildRange)
        {
            queryBuildRange = queryBuildDataSource.addRange(fieldnum(CustTable, AccountStatement));
        }
        // If an account statement has not been set, then use the parameter value to set it.
        if(!queryBuildRange.value())
            queryBuildRange.value(int2str(custAcctStmt));
    }
        
    if(boolInclTax)
    {
        queryBuildRange = queryBuildDataSource.findRange(fieldnum(CustTable, InclTax));
        if (!queryBuildRange)
        {
            queryBuildRange = queryBuildDataSource.addRange(fieldnum(CustTable, InclTax));
        }
        // If flag to include tax has not been set, then use the parameter value to set it.
        if(!queryBuildRange.value())
            queryBuildRange.value(int2str(boolInclTax));
    }        
        
    // Run the query with modified ranges.
    qr = new QueryRun(query);
    ttsbegin;
    while(qr.next())
    {
        tmpCust.clear();
        queryCustTable = qr.get(tablenum(CustTable));
        tmpCust.AccountNum = queryCustTable.AccountNum;
        tmpCust.Name = queryCustTable.name();
        tmpCust.Address = queryCustTable.address();
        tmpCust.CustGroup = queryCustTable.CustGroup;
        tmpCust.Phone = queryCustTable.phone();
        tmpCust.InvoiceAccount = queryCustTable.InvoiceAccount;
        tmpCust.AccountStatement = queryCustTable.AccountStatement;
        tmpCust.InclTax = queryCustTable.InclTax;
        tmpCust.insert();
    }
    ttscommit;
}


Other Example:



BUSINESS LOGIC IN REPORTS

When I discuss "business logic" in this post, I am referring to code that is used to generate data for use in reports. In Dynamic AX 2009 there really is no great way to reuse your X++ code in an SSRS report. This is one reason I recommend that everyone stick with simple query-based reports in Dynamics AX 2009. Of course, we wanted to make this much easier in Dynamics AX 2012 and that is why we created a concept called the Report Data Provider.

 

WHAT IS A REPORT DATA PROVIDER?

It is a X++ code-based way of generating data for reports. This code can use any technique to generate data for Dynamics AX 2012 Reports. It is the correct and supported way to reuse your existing X++ code in Dynamics AX 2012 reports.

 

HOW IT WORKS

The simplest summary is that you create a table – usually a temp table. And then a class – this is known as the Report Data Provider class. When the report is run, the class populated the temp table with data. One the data completely populated it is transferred to the SSRS server.

 

CONSTRUCTING THE TEMP TABLE

First, decide what fields you need in your report. Then create a table with those fields. You MUST assign Extended Data Types to those fields. Then set the TableType property to "TempDB"
Here's a simple table with just two fields
image
Notice that that Extended Data Type has been set for the Name field
image

And for the ID field
image
And then notice that the TableType property has been set on the table to "TempDB".
image

CONSTRUCTING THE DATA PROVIDER CLASS

The simplest RDP class has only three components – they are shown below.
image

The classDeclaration is simple. The RDP Class MUST extend SRSReportDataProviderBase. Also it has a reference to the temp table.
image

The next method is needed for the AX 2012 reporting framework to retrieve data from the temp table. TheSRSReportDataSetAttribute attribute MUST be used to identify the temp table to the framework. The specific name of this method is not important – the attribute is what counts.
image

The processReport() method MUST be implemented when a class extends SRSReportDataProviderBase. In this example, you can see that this method is a completely code-based way of generating data into the report.
image

YOU'RE FINISHED

And that's it for the basics. Now you have a datasource that can be used in an X++ Report.

POSTMAN D365

  Postman is useful to test the behavior of different OData class from/to D365FO. In this post we will see the steps to setup Postman with D...