May 5, 2010

Offer reports as downloadable PDF documents in your Dynamics Ax 2009 Enterprise Portal

One thing I've been tasked with a lot in Ax Enterprise Portal is exposing Dynamics Ax reports through the web  interface. True enough, Microsoft has provided us with the means to expose Ax reports in HTML format, but some serious tweaking is in order to present these (the report query window prompt is, among other things, mysteriously absent in enterprise portal). And when you finally master presenting reports through enterprise portal the client should be disappointed at how it looks. They always are. They have to adjust settings in Internet Explorer to keep the CSS in their printed documents, tweak the CSS and the x++ html generator to make it presentable, and the list goes on.

By now one thing should be clear: Microsoft wants us all to switch to SSRS reporting.

But in my opinion standard Ax reporting is useful and exposing it shouldn't be so hard. Invoices for instance: Customers should really be able to download them from your site, so I have crafted a sample that writes a report to PDF and then offers users to download it through a text and image web link.

I've done this for EP 3.0 as well, and it is actually a lot easier, but the basics remain the same. At the core is the DataSet method X++ code that generates the report.

First, somewhere in your .NET user control*, preferably as the invoice details page loads (The Page_Load method for instance), call your dataset method.


*  In a webdefined control in Ax 3.0 Enterprise Portal (override the layout method instead).

private string InvoiceId;
private string pdfUrl = "about:blank";
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
  InvoiceId = Page.Request.QueryString.Get("IID"); // I passed the invoice id from the grid as a GET parameter
if(!String.IsNullOrEmpty(InvoiceId))
{
  pdfUrl = "http://192.168.88.5:8080/Invoice_" + InvoiceId + ".PDF"; //obviously hard coding isn't the way to go
[...]
try
{
  CustInvoiceJour_DS.GetDataSet().DataSetRun.AxaptaObjectAdapter.Call("CreatePDF", InvoiceId); //This is the call to our DataSet method that initiates the X++ code
  InvoiceLink.NavigateUrl = pdfUrl; // object.
}
catch (Exception)
{


throw;
}
}

Here is the X++ DataSet method that generates the PDF invoice.
NOTE: Remember to host the folder as a site in IIS, or use one of Enterprise Portal's public folders. Also, restrict browsing folder contents and remember to delete sensitive customer data after a short while.
NOTE 2: In Ax 3.0 this code must be in the Web Forms run method.


public str CreatePDF(InvoiceId _invoiceId)
{
Args parameters;
ReportRun reportRun;
//Declare SalesFormLetter and PrintJobSettings objects
SalesFormLetter salesFormLetter;
PrintJobSettings printJobSettings;
 CustInvoiceJour cij;
;

SELECT firstonly cij
 where cij.invoiceId == _invoiceId;

parameters = new Args(ReportStr(SalesInvoice));
printJobSettings = new PrintJobSettings();
printJobSettings.setTarget(PrintMedium::File);
printJobSettings.preferredTarget(PrintMedium::File);
 printJobSettings.preferredMailFormat(PrintFormat::PDF); //Not necessary, but residue from the days this method sent an email instead.
printJobSettings.format(PrintFormat::PDF);
 printJobSettings.fileName(@"\\THINK\pdfhost\Invoice_" + cij.invoiceId + ".PDF"); //Write to the IIS hosted virtual directory

salesFormLetter = new SalesFormLetter_Invoice(false);
 salesFormLetter.updatePrinterSettingsFormLetter(printJobSettings.packPrintJobSettings());

parameters.caller(salesFormletter);
 parameters.parmEnum(PrintCopyOriginal::OriginalPrint); //I had to use PrintCopyOriginal::OriginalPrint, instead of ::Original, as other bloggers recommend. Failing to do so meant, in 2009, that the PDF wasn't saved to the file system. In 3.0 ::Original worked just fine.
parameters.parmEnumType(enumnum(PrintCopyOriginal));
parameters.record(cij);
reportRun = new ReportRun(parameters);
reportRun.init();
reportRun.run();

return "";

} 

Hope this helps someone out there!

Thanks to Brandon George and other bloggers out there.
http://dynamics-ax.blogspot.com/2006_01_01_archive.html

Also: Thank you to Justin Biggs
 https://community.dynamics.com/forums/t/32390.aspx

1 comment:

  1. Just thought of this:
    If you want to show the PDF in the browser window, just use Response.Redirect and pass the user to a ASP.NET page in which you host the following code (in Page_Load):

    FileInfo fi = null;

    fi = new FileInfo("D:\\Customers.pdf");

    if (fi.Exists)
    {
    Response.Clear();
    Response.ContentType = "application/pdf";
    Response.Flush();
    Response.WriteFile(fi.FullName);
    Response.End();

    }

    Reference:
    http://paruvella.spaces.live.com/default.aspx?wa=wsignin1.0&sa=555316674

    ReplyDelete