3

I have a requirement where I need to send an email with attached PDF of Invoice . But I am getting blank PDF. please suggest how can this be rectified.

When I add renderAs = "PDF" , I am getting the Error "PDF generation failed. Check the page markup is valid."

    public PageReference attachCurrentPage() {
            /* At this moment there should be only one attached PDF version,
            so we'll delete all existing before inserting new one.*/
            List<Attachment> existingAttachments = [SELECT Id FROM Attachment WHERE ParentId = :orderId];
           // delete existingAttachments;

            // Insert current page as PDF attachment to the Order.        
            System.PageReference currentPage = ApexPages.currentPage();
            Blob pdfData = currentPage.getContentAsPDF();
            Attachment attach = new Attachment();
            attach.ParentId = orderId;
            attach.Name = 'Invoice_'+System.now()+'.pdf';
            attach.Body = pdfData;
            insert attach;
            return null;        
        }



<apex:page standardController="Order__c" extensions="Cls_Invoice" showHeader="false" sidebar="false" standardStylesheets="true">
<script>
function reload() 
{

   window.top.location='/{!Order__c.id}'; 

}
</script>
<style>
table,th,td
{
padding:5px;
}
</style>

 <table width="100%">
        <tr>
            <th>Customs Invoice</th>
            <!--td rowspan="2"-->
            <th> <apex:image value="{!$Resource.image1}" width="170" height="75"  /> </th> 
        </tr>
        <tr>
            <td>Value for customs purpose only<br/>Tax free export</td> 
            <td>  Date:&nbsp;<apex:outputField value="{Order__c.CreatedDate}"/><br/></td>
<apex:image value="{!$Resource.cancelledimage}"  width="150" height="150"  rendered="{!Order__c.Order_Cancelled__c ==true}"/>
        </tr>     
 </table>


<table width="100%">
<tr>
            <th colspan="2">  Shipping Information</th>
</tr>

</table>
<table width="100%">
<tr>
  <th>Sent to</th>
  <th>Sent from</th>     
</tr>
<tr>
   <td>
      {!Order__c.Shipping_Address__c}
   </td>
   <td>MyAddress   </td>
  <!-- 
  <td rowspan="2">Terms of delivery: DDP
               <br/>Total Gross Weight: {!Order__c.Total_Gross_Weight__c}
                <br/>Total Net Weight: {!Order__c.Total_Net_Weight__c} 
                                <br/>Carrier: DHL
            </td>
   -->
</tr>
 </table >
    <B>  &nbsp; Package Details </B>      
    <apex:form >
        <apex:pageBlock >     
                 <apex:pageBlockTable value="{!OrderProductList}" var="prod">
                    <apex:pageMessages ></apex:pageMessages>                        
                        <apex:column headerValue="Product Description">
                            <apex:outputField value="{!prod.Name}"/>
                        </apex:column>
                        <apex:column headerValue="Quantity">
                            <apex:outputField value="{!prod.Quantity__c}"/>
                        </apex:column>    
                        <apex:column headerValue="Unit Value">
                            <apex:outputField value="{!prod.Price__c}"/>
                        </apex:column>
                        <apex:column headerValue="Sub Total Value">
                                <apex:outputField value="{!prod.Total_Price__c}"/>
                        </apex:column>                      
               </apex:pageBlockTable> 
       </apex:pageBlock>

   <!--  
<table border="1" cellspacing="0">
        <tr>
            <td>Number of items</td>
            <td>{!Order__c.Quantity__c}</td>
        </tr>
        <tr>
           <th>Total</th>
            <th><apex:outputField value="{!Order__c.Total_Price__c}"/></th>
        </tr>
    </table> -->
    <!-- ============================ -->
    <br/>
    <br/>
     <table width="100%">
        <tr>
            <span>
                &nbsp; Reason for Export: Repair/Replacement (goods are delivered free of charge)<br/>
                &nbsp; I declare that the above information is true and correct to the best of my knowledge.<br/>
                <br/>
                 <br/>
                 &nbsp;Signature <br/>
                 &nbsp;{!Order__c.Case__r.Owner.Name}
            </span>
        </tr>
     </table>
     <apex:image value="{!$Resource.ad}" width="150" height="75"  /><br/>
    <center>&nbsp;<apex:commandButton value="Save as attachment" action="{!attachCurrentPage}" status="closer" oncomplete="reload();"   reRender="buttons" />
    &nbsp;<apex:commandButton onclick="window.top.close();" value="Close" />
    &nbsp;<apex:actionStatus startText="(Saving...)" stopText="" onstop=" window.top.close();opener.location.reload(true);"  id="closer"  />   
    &nbsp;<apex:commandButton value="Send Email" action="{!send}"/>  </center>
 </apex:form>
</apex:page>
  • Did you try to create the page via renderAs="pdf" at the page tag? Check if this works. I think the problem is within your vf-page. Try to strip the page down to hello-world level. Then try it again. – Uwe Heim Jul 27 '14 at 9:11
  • I have tried that but even that is not working. – user2703132 Jul 27 '14 at 9:29
  • So the problem is in your page. Strip it down, make it very simple and try it again. If you have shortened your page to a couple of lines, an it still doesn't work, paste your simplified page here so that we can discuss it. But you should be able to find the problem on your own by step-by-step re enabling your previous functionality. The key point is: NOT everything can be rendered as pdf! You may have to adapt or omit something. – Uwe Heim Jul 27 '14 at 9:44
4

One thing to watch out is the use of images stored in static resources. PDF rendering engine doesn't like them. Start with deleting / commenting out the image-related tags.

If it fixes it - you can still use images you've uploaded to Documents tab (as long as they're marked as "externally available". In my current org I've uploaded logos to production's Documents folder and all email templates point to production link. Looks off, you'd maybe want to point to current sandbox but in dev sandboxes the Documents will always be empty. So it becomes a bit of preference, do you want templates that work everywhere or are you after clear distinction that email from sandbox is OK to not have images so nobody can do something with it by mistake.


Apart from that - ditch the JavaScript, <apex:form>, <apex:commandButton> and other "interactive" elements. Buttons will render (like <apex:detail> will) but it doesn't mean it's a good idea.

4

The problem is in the visualforce page, not in the APEX. As verified, some markup can't be rendered as pdf. To fix, simplify your page until you get an output with renderAs="pdf".

After that works (and at least a static "hello world" will) go on iteratively re enabling contend until you pin point the exact reason.

or start the other way around

Start to remove all image-related tags and script-tags. Don't use JavaScript in PDF. Also remove all command-buttons like apex:commandButton. Keep in mind that dynamic stuff (buttons, script, etc.) does not belong into PDF. If you need that for other purpose, separate it into a different page.

This way or another: renderAs="pdf" has to work first. Then you can proceed with the attachment.

  • Right now I see only the page as source of the issue. My RenderAs verification seems to proof that true. But fore sure you are right: these are blind shots and gut feelings. So let's see what happens ;-) – Uwe Heim Jul 27 '14 at 15:42
  • When I add renderAs = "PDF" , I am getting the Error "PDF generation failed. Check the page markup is valid." – user2703132 Jul 28 '14 at 7:44
  • That's exactly what I have expected. Did you try what I suggested to (temporarily!) simplify your page-markup until the error disappears? Try it, and you'll find out precisely what's the problem. Start with all script-tags! Don't use JavaScript in PDF! Also remove all command-buttons like apex:commandButton. Keep in mind that dynamic stuff (buttons, script, etc.) does not belong into PDF. If you need that for other purpose, separate it into a different page. – Uwe Heim Jul 28 '14 at 8:16
  • @crmprogdev now it seems to be obvious, doesn't it? – Uwe Heim Jul 28 '14 at 12:15
0

To add to what's been said and provide you with a detailed reference that will be useful in the future, I refer you to this document: Best Practices for Rendering PDFs. In reading it you'll see that apex tags I see in your code like <apex:pageBlock >, <apex:pageBlockTable>, <apex:commandButton>, <apex:actionStatus>, <apex:form> and <apex:pageMessages> are all Components That Are Unsafe to Use in a PDF while <apex:column> is listed as a Component to Use with Caution in a PDF.

Generally speaking, its best to stick with Standard HTML 4.1 tags for your structure and use Tables while avoiding Apex PageBlocks. As others have pointed out, interactive content does not belong in a PDF and will not render as intended.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.