[SalesForce] Make visualforce page (pdf) available outside Managed Package

Is it possible to exclude a visualforce page that will be used for rendering a PDF from a managed package?

The reason is, we have a standard PDF layout, but we want to give our clients the possibility in changing the layout of the pdf, in order to create their own branded version of the pdf.

I was thinking about, not including the pdf in a package, not including the button on the page layout that generates the pdf either (which generates the pdf, and adds it as an attachment to the SObject), and just create an unmanaged "support" package that includes the default pdf, and the button (the button calls a webservice method via javascript).

But then comes the problems i'm thinking about.

  • In the apex webservice method, I reference the page via Page.PDFPageName, but since the page isn't included in the package, i'm not sure if the deployment would fail.
  • Some use cases require the pdf to be generated from code (in some cases, when the sobject gets made, the pdf gets autogenerated)

How would one start of implementing this, (if its possible at all)

Best Answer

The way we did this in FinancialForce (as mentioned by eyescream above) was to include the VF page in the managed package, but ensure that the controller and all methods the page called by the page (same with any components you use) were marked as global. So the button defaults to using that VF page, all good.

When the customer wants to override it they clone the page (copy + paste the contents), change the 'c:' references to the package namespace, eg. 'myns:' and save. The page should work as before. Then by having a custom setting defined to override the print VF page to be used we have code behind our print button that checks if there's a value, if there is it constructs the PageReference to redirect to from that (passing in the id of the record to print, so no using Page.PDFPageName), otherwise it uses the managed package version (Page.PDFPageName in your case). So something like this in the controller:

global PageReference getPrintPage()
{
    Id invoiceId = stdController.getId();
    PageReference printPage = Page.PDFPageName;      

    String customPageUrl = MySettings__c.getInstance().CustomPrintPage__c;
    if( !String.isBlank( customPageUrl ) )
    {
        printPage = new PageReference( customPageUrl );
    }

    printPage.getParameters().put( 'id', invoiceId );

    return printPage.setRedirect( true );
}

Your code to attach the PDF to the record (or in our case mark a document as 'Printed') lives in the controller so will still be called by the overridden page since it's using the same controller behind the scenes.

Related Topic