Report Data Provider Based SSRS Report in D365 F&O - X++ Code

Rumman Ansari   Software Engineer   2023-07-04   2625 Share
☰ Table of Contents

Table of Content:


Report Data Provider Based SSRS Report in D365 F&O - X++ Code

Create a SSRS report

In the UI you have to take/take customer group and based on that customer group all customer will appear in the report.

In the report below fields should be there (Customer Account, Customer Name, Customer Address)

Solution

Step 1: First Identify all those fields and related tables, You can write SQL statements to identify all those fields. If multiple tables will be there then you have to join those tables. To joins tables there should have relationship between tables otherwise join will not be possible. But join is required to merge data between two tables.


SELECT * FROM CUSTGROUP

SELECT * FROM CUSTTABLE

SELECT  ACCOUNTNUM, CUSTGROUP, PARTY FROM CUSTTABLE

SELECT NAME, RECID, PRIMARYADDRESSLOCATION  from DirPartyTable 

SELECT ADDRESS, LOCATION from LOGISTICSPOSTALADDRESS


SELECT
custTable.ACCOUNTNUM,
dirPartyTable.NAME,
logisticPostalAddress.ADDRESS from CUSTTABLE custTable
INNER JOIN DIRPARTYTABLE dirPartyTable ON custTable.PARTY = dirPartyTable.RECID
INNER JOIN LOGISTICSPOSTALADDRESS logisticPostalAddress ON dirPartyTable.PRIMARYADDRESSLOCATION = logisticPostalAddress.LOCATION
WHERE custTable.CUSTGROUP = 'BULK'
 

Step 2: To create a RDP based report basically you need a data provider class. Data provider class is mandatory.

Two mandatory method in Data Provider Class:

  • processReport()
  • getReportData()
To connect DP class and Contract class you have to use: [SRSReportParameterAttribute(classStr(CustomerAccountNameAddressContract))]

[SRSReportParameterAttribute(classStr(CustomerAccountNameAddressContract))]
class CustomerDataDP extends SRSReportDataProviderBase
{
    CustomerAccountNameAddressTemp customerAccountNameAddressTemp;
    CustomerAccountNameAddressContract customerAccountNameAddressContract;

    public void processReport(){
  
     customerAccountNameAddressContract = this.parmDataContract();
     custGroupId = customerAccountNameAddressContract.parmCustGroup();

     Query query = new Query();
     QueryBuildDataSource custTableQbds, dirPartyTableQbds, logisticsPostalAddressQbds;
        QueryBuildRange customerGroupRange;

     custTableQbds = query.addDataSource(tableNum(CustTable));
     dirPartyTableQbds = custTableQbds.addDataSource(tableNum(DirPartyTable));
     logisticsPostalAddressQbds = dirPartyTableQbds.addDataSource(tableNum(LogisticsPostalAddress));

      custTableQbds.joinMode(JoinMode::InnerJoin);
      dirPartyTableQbds.joinMode(JoinMode::InnerJoin);
      
      //custTableQbds.relations(true);
      //dirPartyTableQbds.relations(true); 
       dirPartyTableQbds.addLink(fieldNum(custTable, party) , fieldNum(DirPartyTable, RecId));
       logisticsPostalAddressQbds.addLink(fieldNum(DirPartyTable, PrimaryAddressLocation) , fieldNum(LogisticsPostalAddress, Location));
        
        customerGroupRange = custTableQbds.addRange(fieldNum(CustTable, CustGroup));
        customerGroupRange.value(queryValue(custGroupId));


        QueryRun queryRun = new QueryRun(query);

        ttsbegin;
        while(queryRun.next()){
            CustTable custTable = queryRun.get(tableNum(CustTable));
            DirPartyTable dirPartyTable = queryRun.get(tableNum(DirPartyTable));
            LogisticsPostalAddress logisticsPostalAddress = queryRun.get(tableNum(LogisticsPostalAddress));
            customerAccountNameAddressTemp.AccountNum = custTable.AccountNum;
            customerAccountNameAddressTemp.Name = dirPartyTable.Name;
            customerAccountNameAddressTemp.Address = logisticsPostalAddress.Address;

            customerAccountNameAddressTemp.insert();
        }        
        ttscommit;
    
    }

    [SRSReportDataSetAttribute(tableStr(CustomerAccountNameAddressTemp))]
    public CustomerAccountNameAddressTemp getReportData(){
    select * from customerAccountNameAddressTemp;
        return customerAccountNameAddressTemp;
    }

}

Step 3: If you want to take parameter from the UI then you have to create a contract class. Also you have to connect Data provider class and Contract class with the Attribute. and to take the parameter inside the data provider class you have to create object of the contract class inside data provider class.


[DataContractAttribute]
class CustomerAccountNameAddressContract
{
    CustGroupId custGroup;
    [DataMemberAttribute("Cust Group")]

    public CustGroupId parmCustGroup(CustGroupId _custGroup = custGroup){
        custGroup = _custGroup;
        return custGroup;
    }

}

Step 4: Then you have to create a report and you have to add data source and and design of the report.

Step 5: At last you have to create a output menu item to and link to the SSRS report to the object of the menu item.

Step 6: Then after that you have to deploy the report.

Step 7: Make menu item as startup object.

Step 7: Last you have to build and run the project.


Note:

Controller class:

Controller class is not always required but for completed SSRS report you need to use the controller class. The controller class is responsible for setting up the SSRS report design. When you are using Controller class in your Report you have to specify the Controller class name inside your output menu item.

Sample code for Controller class:


class CustomerAccountNameAddressController extends SrsReportRunController
{
    public static void main(Args _args){
        CustomerAccountNameAddressController ct = new CustomerAccountNameAddressController();
        ct.parmReportName(ssrsReportStr(SSRSReportDPExample, Report));
        ct.parmArgs(_args);
        ct.parmShowDialog(true);
        ct.startOperation();
    
    }

}

Below is a table you can see objects required for a SSRS report.

Minimum object in a SSRS report With Controller Class With Controller and UI Builder Class
rdp with no controller
Figure: Without controller you can run a simple basic report.

SSRSReportDPExample is a report.

menu item for ssrs report directly
Figure: menu item for ssrs report directly

rdp based report objects
Figure: Based on situation you can use controller.

menu item for controller class
Figure: menu item for controller class

If you want to modify the design and want to add custom fields and lookup then you can use UI builder class.