Creating a new Sales Invoice report design using SSRS and X++ is quite a common task. In this post, I'll try to describe how you can do this in Dynamics 365 Finance and Operations.
I will use "DEVTutorial" prefix for new elements
Let's start with a data provider. We should create a new class and extend it from the standard SalesInvoiceDP. In this case, we can add additional fields that are relevant only for our report.
[SRSReportParameterAttribute(classStr(SalesInvoiceContract))]
class DEVTutorialSalesInvoiceDP extends SalesInvoiceDP
{
protected void populateSalesInvoiceTmp(CustInvoiceJour _custInvoiceJour,
CustInvoiceTrans _custInvoiceTrans,
TaxSpec _taxSpec,
CustPaymSchedLine _custPaymSchedLine,
CustTrans _prepaymentCustTrans,
TaxTrans _prepaymentTaxTrans)
{
super(_custInvoiceJour, _custInvoiceTrans, _taxSpec, _custPaymSchedLine, _prepaymentCustTrans, _prepaymentTaxTrans);
//populate additional fields in salesInvoiceTmp here
//salesInvoiceTmp.MyField = '';
//this method is called for main lines and also for all linked tables
//please note, that it will not be called if there are already some data exist in salesInvoiceTmp table for the selected Sales order, you need to delete existing records }
protected void populateSalesInvoiceHeaderFooterTmp(CustInvoiceJour _custInvoiceJour, CompanyInfo _companyInfo)
{
super(_custInvoiceJour, _companyInfo);
//populate additional fields in salesInvoiceTmp here
//salesInvoiceHeaderFooterTmp.MyField = '';
} }
Then add a new SSRS report to our project
We need to add Datasets for this report. In the standard system we have 4 sales invoice datasets, let's add them all.
Dataset name | Query |
---|---|
SalesInvoiceDS | SELECT * FROM DEVTutorialSalesInvoiceDP.SalesInvoiceTmp |
SalesInvoiceHeaderFooterDS | SELECT * FROM DEVTutorialSalesInvoiceDP.SalesInvoiceHeaderFooterTmp |
SalesInvoiceLocalizationDS | SELECT * FROM DEVTutorialSalesInvoiceDP.SalesInvoiceLocalizationTmp |
DocuBrandDetailsDS | SELECT * FROM DEVTutorialSalesInvoiceDP.SysDocuBrandDetailsRegular |
At the end you should have something like that:
Then let's add a new Precision Design(Report)
Modify its properties: Size to standard A4 210x297mm and all Margins to 0.
Add the following sections
For the header, let's add a logo from Document branding
=First(Fields!Image1.Value, "DocuBrandDetailsDS")
and some client information
=First(Fields!SalesId.Value, "SalesInvoiceHeaderFooterDS") & vbcrlf &
First(Fields!InvoiceDate.Value, "SalesInvoiceHeaderFooterDS") & vbcrlf &
First(Fields!InvoicingAddress.Value, "SalesInvoiceHeaderFooterDS")
Add a new Tablix control with SalesInvoiceDS dataset
Adjust Row visibility to the following formula "=IIF(Fields!ItemId.Value = "", true, false)" as SalesInvoiceDS may contain data from linked tables(like payment schedule)
Let's also add a totals section. The resulting design should look like this
A sales invoice can be used in a Print management module. In order to connect our report to this module, we need to subscribe to two events(create 2 new classes):
Update 25/11/2021. A more detailed description can be found in the following blog How to Add New Report Format to Print Management
[ExtensionOf(classstr(PrintMgmtReportFormatPopulator))]
final class PrintMgmtReportFormatPopulatorDEVTutorial_Extension{ protected void addDocuments()
{
this.addStandard(PrintMgmtDocumentType::SalesOrderInvoice);
next addDocuments();
} }
final static class PrintMgmtDocTypeDEVTutorial_EventHandler{ [SubscribesTo(classstr(PrintMgmtDocType), delegatestr(PrintMgmtDocType, getDefaultReportFormatDelegate))]
public static void getDefaultReportFormatDelegate(PrintMgmtDocumentType _docType, EventHandlerResult _result)
{ switch (_docType)
{
case PrintMgmtDocumentType::SalesOrderInvoice:
_result.result(ssrsReportStr(DEVTutorialSalesInvoice, Report));
break;
} } }
That is all. It is time to test our report.
Build and deploy the report. Then, before the test, you need to add it to the print management settings. In order to do this - run the following job
class DEVTutorialPopulateReports
{ public static void main(Args _args)
{
PrintMgmtReportFormatPopulator::construct().populate();
}}
https://usnconeboxax1aos.cloud.onebox.dynamics.com/?mi=SysClassRunner&cls=DEVTutorialPopulateReports
Next step is to add a logo to our report. Go to the Document images form and upload the image. Then go to the Branding details form and select this image.
To print the invoice go to the Accounts receivable - Invoice journal, select Document - Original preview and you should see our sample report:
There may be a question of what is the future of SSRS reporting. Considering the latest news, I think that its popularity may grow. Microsoft recently released Power BI Paginated Reports that are completely based on SSRS "rdl" files. Technically a new Power BI Paginated Reports Builder is an old SSRS report builder with a new name(yes, another name change).
Check, for example, this recent course Power BI Paginated Reports in a Day course. Almost all its modules(except maybe 04) are relevant to D365FO development.
And this Bear in the previous picture is not just a funny picture, it is an official mascot of Power BI Paginated Reports. So with a new name and a new Bear, I hope the popularity of SSRS may grow.
If you watch this "Power BI Paginated reports Day course" you may feel that SSRS is cool(presentation is really great). However, the last main update for Report Builder was 10 years ago and the current version has some issues. Just some of them:
So there are a lot of things that can be improved, and I hope Microsoft will invest in it.
Real-life invoice reports can be quite complex and require a lot of efforts to create them. However, as we see, creating a simple Sales Invoice design is not a complex task. You can use the project above as a starting point(another option to consider is to install modern design templates).
If you have some hints for SSRS report development, don't hesitate to post a comment. The project used in this post can be downloaded from my GitHub(you can download a model to a temporary folder and add elements from it to your project using "Add - Existing item.." command)
Similar posts: