Appending pages to SSRS Pdf print management reports

More than once, it happened to me that a customer wanted to insert at the end of some PDF reports of the print management (invoices, confirmations, etc.) one or more pages containing different terms and conditions.

The first solution that can come to mind is to add these conditions directly to the report layout and repeat them for each requested report. However it is not uncommon that this list of clauses is the same for all reports and at the same time is very long. In cases like this it would not be a bad idea to have a single and already formatted text.

The ideal would be to have a pdf that contains the clauses to be able to hang directly to a report. Doing such a thing is not extremely complicated in D365fo. Let’s see how it can be done.
First of all I used a well known .NET library for manipulating pdf: PDFSharp (version 1.32). This assembly has to be added as a reference of our project.

Then I created a class for merging pdf:

public class PdfMerger
{
    private PdfSharp.Pdf.PdfDocument outputPDFDocument = new PdfSharp.Pdf.PdfDocument();

    public void resetOutputDocument()
    {
        outputPDFDocument = new PdfSharp.Pdf.PdfDocument();
    }

    public System.Byte[] getOutputDocumentAsBytes()
    {
        using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream())
        {
            outputPDFDocument.Save(memoryStream);
            return memoryStream.ToArray();
        }
    }

    public System.IO.Stream getOutputDocumentAsStream()
    {
        System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();
        outputPDFDocument.Save(memoryStream, false);
        return memoryStream;
    }

    public void addStream(System.IO.Stream _stream)
    {
        int                         j;
        int                         pageCount;

        PdfSharp.Pdf.PdfDocument    inputPDFDocument;
        PdfSharp.Pdf.PdfPages       pdfPages;

        inputPDFDocument = PdfSharp.Pdf.IO.PdfReader::Open(_stream,
                PdfSharp.Pdf.IO.PdfDocumentOpenMode::Import);
        outputPDFDocument.set_Version(inputPDFDocument.get_Version());

        pageCount = inputPDFDocument.get_PageCount();

        if (pageCount > 0)
        {
            pdfPages = inputPDFDocument.get_Pages();
            for (j = 0 ; j < pageCount; j++)
            {
                outputPDFDocument.AddPage(pdfPages.get_Item(j));
            }
        }
    }

    public void addByteArray(System.Byte[] _data)
    {
        using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(_data))
        {
            this.addStream(memoryStream);
        }
    }

    public void addResource(SysElementName _resourceName)
    {
        Binary          binary;
        ResourceNode    resourceNode = SysResource::getResourceNode(_resourceName);
        container       data = SysResource::getResourceNodeData(resourceNode);

        binary = Binary::constructFromContainer(data);
        using (System.IO.MemoryStream memoryStream = binary.getMemoryStream())
        {
            this.addStream(memoryStream);
        }
    }

    public void addFile(FilePath _filePath)
    {
        this.addByteArray(System.IO.File::ReadAllBytes(_filepath));
    }

}

Now we need a couple of event handlers and the work is done:

public class SrsProxyHandler
{
    private readonly str                 reportPath;
    private readonly SRSReportFileFormat fileFormat;

    System.Byte[]                        reportBytes;
    Array                                reportFiles;

    private void new(XppPrePostArgs _args)
    {
        reportPath = _args.getArg("_reportPath");
        fileFormat = _args.getArg("_fileFormat");
    }

    public boolean shouldAppendPdf()
    {
        return fileFormat == SRSReportFileFormat::PDF &&
            System.IO.Path::GetFileName(reportPath) == ssrsReportStr(SalesInvoice, Report);
    }

    public System.Byte[] parmReportBytes(System.Byte[] _reportBytes = reportBytes)
    {
        reportBytes = _reportBytes;
        return reportBytes;
    }

    public Array parmReportFiles(Array _reportFiles = reportFiles)
    {
        reportFiles = _reportFiles;
        return reportFiles;
    }

    public System.Byte[] getReturnValue()
    {
        PdfMerger merger = new PdfMerger();
        merger.addByteArray(reportBytes);
        merger.addResource(resourceStr(SalesConditions));

        return merger.getOutputDocumentAsBytes();
    }

    public void writeToFiles()
    {
        PdfMerger merger = new PdfMerger();
        int       i;

        for (i = 1 ; i <= reportFiles.lastIndex() ; i++)
        {
            merger.addFile(reportFiles.value(i));
            merger.addResource(resourceStr(SalesConditions));

            System.IO.File::WriteAllBytes(reportFiles.value(i), merger.getOutputDocumentAsBytes());

            merger.resetOutputDocument();
        }
    }

    [PostHandlerFor(classStr(SrsProxy), methodStr(SrsProxy, renderReportToFile))]
    public static void SrsProxy_Post_renderReportToFile(XppPrePostArgs _args)
    {
        SrsProxyHandler handler = new SrsProxyHandler(_args);
        if (handler.shouldAppendPdf())
        {
            handler.parmReportFiles(_args.getReturnValue());
            handler.writeToFiles();
        }
    }

    [PostHandlerFor(classStr(SrsProxy), methodStr(SrsProxy, renderReportToByteArray))]
    public static void SrsProxy_Post_renderReportToByteArray(XppPrePostArgs _args)
    {
        SrsProxyHandler handler = new SrsProxyHandler(_args);
        if (handler.shouldAppendPdf())
        {
            handler.parmReportBytes(_args.getReturnValue());
            _args.setReturnValue(handler.getReturnValue());
        }
    }

}

In my example I append to the SalesInvoice report a pdf stored in the AOT a resource named “SalesConditions”, but it’s possible to change the “shouldAppendPdf” method for including different reports.

2 thoughts on “Appending pages to SSRS Pdf print management reports

  1. It is the class “SrsProxyHandler” which executes the code and appends a pdf to a report. In my sample you can try just by printing a SalesInvoice

    Like

Leave a comment