Microsoft Dynamics AX 2012
Before customizing SYS-layer reports, it is strongly encouraged to go through how the reporting components interact with each other. You should have clear understanding of static parameters, Visual studio designs, controller class, RDP class and dynamic query.
Nancy – developer
There is a SYS-layer SSRS report which shows information about customer transactions. Nancy is working in USR layer to add some additional changes particular to Eastern European country. The report which Nancy is working on is a simple list precision design report which shows customer information and their transactions. Nancy was asked to make some design changes in the report to add additional transactional columns in the body. Nancy being new to report development doesn’t know how to approach the design, what choices to make?
So basically you want to extend the design and add additional fields to it.
There are 3 ways you can extend the design:
Approach 1: Use the SYS-layer design and add additional columns to the table which will be shown only for eastern European country context
Approach 2: Create a new design by duplicating the SYS-layer design within the same report and then add those additional columns in the new design
Approach 3: Create a brand new report itself and then copy paste the SYS-layer design in the new report and add those additional columns in the new design in the new report.
All the above mentioned 3 approaches have pros and cons which is discussed in detail below
If you want to show those additional columns when you are logged in only in Eastern Europe country context then the report design should know what country context the report is running currently. One thing to remember is, there is no direct support from the framework to enable and disable report design elements by using any country context metadata. So, it is the responsibility of the application developer to pass the country context from AX client to the design.
How do you do that?
Option A) Create a Boolean static hidden parameters in the visual studio and set the value based on the some country context check in the controller class in preRunModifyContract() and use that parameter to enable/disable design elements accordingly.
Option B) Add a temp table field to hold the country context value and use that value in your design to control the visibility of the fields.
• If the changes are more complex and if you have to customize the report for different countries (LT, LV, CZ, HU, IN, BR, CH) as well, then the whole report design becomes cumbersome with each field/column tied to a country context parameter or some Boolean parameter and maintaining the report design becomes difficult in long run.
• Any changes done to the SYS design will have to carefully examined because the design is shared across all the countries.
• Moreover there are no help docs in the design which will clearly tell us what field is bound to what country context, unless we go and look in to the hidden expressions.
Factors which drive this approach:
• Limited design changes.
• Report behaves pretty much same like the SYS report, not just the design alone, even the parameter dialog as well.
In this approach, there is going to be multiple designs one per each country context within the same report and the controller class plays a major role in selecting which report design to run based on the country context in prePromptModifyContract() or in main(). Here, the design doesn’t have to know about which country context it is running, if the controller knows, and then it will redirect the call to the appropriate report designs. Pretty much most of the document reports in GLS layer follows this approach. This gives some control over the design elements, parameter dialog, query, temp table, RDP class.
Here you will have to duplicate the sys design. So any changes or bug fixes done for the SYS design may need to be done on the duplicated design as well.
Factors which drive this approach:
• More customized design changes
• The report contract parameters are same across all the design or all the countries
• Report dynamic query is same for all the report design or all the countries
• Report dataset remains the same as that of SYS and bound to the same RDP class and temp table.
• One RDP class for all country specific design.
In this approach there is going to be a new report for each country with one design in each of them. Here, the controller class plays a major role in selecting which report and design to run based on the country context in prePromptModifyContract(). Even here, the design doesn’t have to know about which country context it is running, if the controller knows, then that is enough. This gives maximum control over the design elements, parameter dialog, query, temp table, RDP class.
Here you will have to create a new design or duplicate the SYS design. So any changes or bug fixes done for the SYS design should also be done on the new design as well. Additional report objects should be maintained
Factors which drive this approach:
• More customized design changes with complete flexibility
• The report contract parameters can be different between countries
• Report dynamic query can be different across countries
• Report RDP class, temp table can be different across countries
The reason why it is mentioned ‘can be’ in the above statements is, if we want to reuse some of the pieces like contract, RDP class, temp table, controller, etc. across different reports, even that is possible.
All these reports share the same dynamic query, same temp table, same controller classes and partially RDP class as well.
Nancy suddenly got an idea, that she can use two datasets one for each country and each dataset is pointing to two different RDP class and use each dataset in separate designs accordingly. But she is not sure of the complications? Are there any complications in taking this approach when compared to the other approaches which were mentioned above?
Let’s assume her report looks like this
1) Dataset1_PL - points to a RDP class specific to Poland
2) Dataset2 _CZ - points to a RDP class specific to Czech
1) Design1_PL - Uses dataset1_PL and has a unique design layout
2) Design2_CZ - Uses dataset2_CZ and has a unique design layout
Report parameters get populated from the both dataset1_PL and dataset2_CZ
The problem with this approach is when you launch the Poland report; you would still see the parameters from the Czech report, because the parameters are shared across the design. So what you have to do is manually hide those parameters in the controller class before prompting the dialog. But the problem is, we won’t be able to get the Dataset2_CZ contract reference in the controller, because the controller always gives the contract reference of the first dataset. So we won’t be able to hide the parameters specific to Czech report. So having multiple datasets one for each country with the same Report object won’t work
Nancy is thinking of creating two similar SSRS Reports, one for each country (PL and LT) and she is thinking whether to use same controller class and MenuItems for both the reports and redirect the call to the appropriate report based on the country context.
What all she should consider before taking that decision?
Before we take that path we have to analyze why we have to do it that way.
• How much common logic is being used across all the country specific report?
• The reports which will be launched from the Controller, are part of the same SSRSReport with additional designs?
• Whether you want to launch separate reports based on the country context?
In general if the controller is being used to just launch different report designs based on the country context which is part of same report object, then, yes you can use it.
When you can think there is a significant difference between the contract classes and query which is being used by those reports then the recommendations is to use different controller class for each country specific report and have a separate menu item pointing to the controller class. The reason is, if the contract classes are different then you would have to manipulate the contract class separately for each country using the below logic.
If (isLegalEntityInCountryRegion([#isoCountryCode]) )
// Get the appropriate contract parameters
// Get the appropriate query
// some logic …
You have to write the above code in each and every place you need to modify which adds some overhead. Instead if you have a separate controller class for each country then it will be simple and easy to maintain. This gives more flexibility from security point of view as well.