Hi guys, Today in this blog I will be demonstrating the procedure for the SSRS Reports development and customization in D365FO. Before proceeding with the Development or customization make sure that you have created a new model for your customization since we will be using extensions approach in our customization because An extension enables you to add functionality to existing model elements and source code.

Coming back to the main objective of this blog which is to Develop SSRS reports in D365. One point to keep in mind is that there is no change on How you develop query based report and RDP based report in D365FO . The only change is you have to use extensions for standard report. If you are developing brand new report based on custom tables, there is no change. So in this Blog I will discuss How to customize an existing SSRS Report in D365 using Extensions approach step by step:

Step#1: The first step is to create a new model, Below are the steps to create a new model:

  1. Navigate to Dynamics 365 > Model Management > Create model:
  2. Provide the Model name and other information:
  3. In select package, Create new package so that this model is compiled into its own separate assembly:
  4. Now select the referenced packages which are required, you can also update this in future through Model management and update model parameters (Make sure that all the required packages are referenced in you model):
  5. Once the above steps are done the summary window will open, you can mark the check box to make this as a default model for your new projects (also you can change the model from project properties).

Once the Model is created, we will be doing all our development and customization in this newly created Model.

Step#2: Create a new project in Visual Studio,

  1. Navigate To File > New > Project:
  2. Select Dynamics 365 > Unified Operations, Provide a suitable name for your Project and click OK:
  3. Once the New Project is created, make sure that the Model you created in the first step is selected as can be seen in the below screen shot (You can also select the model by going to Project properties and selecting an appropriate Model):

Step#3: Duplicate the existing report into the created Project (For the demonstration purpose I will be Modifying Purchase order Report):

  1. Duplicate the PurchPurchaseOrderReport in the Application explorer > AOT > Reports > PurchPurchaseOrder as shown in below screen shot:
  2. Rename the report and provide any appropriate name:

Step#4: Modify  the report design according to the business requirement:

Step#5: Create a new Extension class that extends the standard report controller class.

Use the extended class to load the custom design.

class PurchPurchaseOrderControllerExt extends PurchPurchaseOrderController
   public static PurchPurchaseOrderControllerExt construct()
       return new PurchPurchaseOrderControllerExt();


Add a main method that refers to the custom report design. (You can just copy the main method from the standard solution and add references to the new Controller class.)

public static void main(Args _args)
    SrsReportRunController          formLetterController = PurchPurchaseOrderControllerExt::construct();
    PurchPurchaseOrderControllerExt    controller;
    if (TradeFormHelper::isCalledFromForm(_args, formStr(VendPurchOrderJournalListPage)))
    controller = formLetterController;
    controller.initArgs(_args, ssrsReportStr(AXPPurchPurchaseOrder,Report));
    if(classIdGet(_args.caller()) == classNum(PurchPurchOrderJournalPrint))
       formLetterController.renderingCompleted+= eventhandler(purchPurchOrderJournalPrint::renderingCompleted);

I faced an issue that the new report design was not being displayed even after creating the above extension class and refering to the new report design, Upone some analysis i found a solution which resolved this issue by adding the below outputReport method:

protected void outputReport()
   SRSCatalogItemName  reportDesign;
   reportDesign = ssrsReportStr(AXPPurchPurchaseOrder,Report);

Step#6(Optional): This step is for the case if you have to modify the report data source also i.e. in case you have added any new fields to the report Datasource or you have to modify any existing data in the Tmp table:

For demonstration purpose lets consider that we have to add a new field to the Report Header named as Terms and conditions, So First we would create the extension of our temp table:

  1. Navigate to Application explorer> AOT> Data model> Tables:
  2. Add the required fields to the Temp Table extension:
  3. Now go the report and reset the report data set to Use the newly added column in the report design.
  4. In Order to Add the X++ logic to populate the newly added field, Create a new X++ Report handler class:
    1. In my case I created the below class
      class AXPPurchPurchaseOrderHandler
    2. Now, we have two different ways to Populate the data in the Report handler class:
      1. Add a temp table Inserting event. Apply this technique for row-by-row calculations. Below is the logic that i used which may very according to the requirement:
        [DataEventHandlerAttribute(tableStr(PurchPurchaseOrderHeader), DataEventType::Inserting)]
        public static void PurchPurchaseOrderHeaderInsertEvent(Common c, DataEventArgs e)
               PurchPurchaseOrderHeader    tempTable = c;
               FormLetterRemarks           formLetterRemarks;
               formLetterRemarks = formLetterRemarks::find(‘en-us’, FormTextType::PurchPurchaseOrder);
               tempTable.TermsAndConditions = formLetterRemarks.Txt;

        2. Add a data processing post-handler. Apply this technique for bulk insert operations that use a single pass over the result set of the standard solution.

        [PostHandlerFor(classStr(PurchPurchaseOrderDP), methodstr(PurchPurchaseOrderDP, processReport))]
        public static void TmpTablePostHandler(XppPrePostArgs arguments)
             PurchPurchaseOrderDP dpInstance = arguments.getThis() as PurchPurchaseOrderDP;
             PurchPurchaseOrderHeader tmpTable = dpInstance.getPurchPurchaseOrderHeader();
             FormLetterRemarks           formLetterRemarks;
             while select forUpdate tmpTable
                  formLetterRemarks = formLetterRemarks::find(‘enus’FormTextType::PurchPurchaseOrder);
                    tempTable.TermsAndConditions = FormLetterRemarks.Txt;


Step#7: Create extension for the existing menu items:

  1. Navigating to the Application Explorer> AOT> User interface> Menu items> output> PurchPurchaseOrder > Right click and create extension.
  2. Also make sure to set the value of the Object property to PurchPurchaseOrderControllerExt to redirect user navigation to the extended solution.


This is all with the modification of the existing SSRS report in D365, and now we can view our modification by executing the report from D365FO. Hope this blog is helpful for you guys, stay tuned for more upcoming Technical blogs on D365.


Leave a Reply

Recent Comments