1

I just started learning Apex recently, and there's still a lot of topics that are hard for me to navigate at this time. I've searched everywhere for a solution that works, but I still haven't been able to figure it out.

I've created a button on my Salesforce org that renders a PDF from a visualforce page, and attaches it to the record as a File. This is to be used with Docusign later on to capture signatures for contracts. The problem is that, when using merge fields in the VF page, they either do not show at all, or I get this exception: "sObject row was retrieved via SOQL without querying the requested field".

Now, the exception explicitly says that I need to query the fields, and this is what I've found I need to do to make this work, but I have not been able to figure out how to do this properly. I've tried running a query in several places in my controller extension to no avail (I am using a standardController that SF created for my custom object).

Here's my extension's code:

public class attachPDFToQuote {
    
    public final i360__Quote__c q {get; set;} //Quote object
     
   
    
    //constructor
    public attachPDFToQuote (ApexPages.StandardController stdController) {
        q = (i360__Quote__c)stdController.getRecord(); 
        
        /* for(i360__Quote__c query:[SELECT Id, Correspondence_Name__c, Name FROM i360__Quote__c WHERE Id=: q.Id]){
      
      System.debug(i360__Quote__c.Correspondence_Name__c);
      }*/
        
    }
     
    
    public PageReference attachPDF() {
    
   /* for(i360__Quote__c query:[SELECT Id, Correspondence_Name__c, Name FROM i360__Quote__c WHERE Id=: q.Id]){
      
      System.debug(i360__Quote__c.Correspondence_Name__c);
      }*/
    
        //generate and attach the PDF document
        PageReference pdfPage = Page.ProjectAgreement;
        Blob pdfBlob; //create a blob for the PDF content
        if (!Test.isRunningTest()) { //if we are not in testing context
            pdfBlob = pdfPage.getContent(); //generate the pdf blob
        } else { //otherwise, we are in testing context. Create the blob manually.
            pdfBlob = Blob.valueOf('PDF');
        }
        
        
        ContentVersion cvAttach = new ContentVersion(ContentLocation= 'S');
        cvAttach.PathOnClient= 'Project Agreement.pdf';
        cvAttach.Title= 'Project Agreement';
        cvAttach.VersionData= pdfBlob;
        insert cvAttach;
        
        Id conDoc = [SELECT ContentDocumentID FROM ContentVersion WHERE Id=: cvAttach.Id].ContentDocumentId;
        ContentDocumentLink ConDocLink = new COntentDocumentLink();
        conDocLink.LinkedEntityId= q.Id;
        conDocLink.ContentDocumentId= conDoc;
        conDocLink.ShareType= 'V';
        insert conDocLink;
       
        
        //redirect the user
        PageReference pageWhereWeWantToGo = new ApexPages.StandardController(q).view(); //redirect the User back to the Quote detail page
        pageWhereWeWantToGo.setRedirect(true); //indicate that the redirect should be performed on the client side
        return pageWhereWeWantToGo; //send the User on their way
    }

}

I kept the commented code where I try to query the object fields so they show in VF. I also tried a couple of different ways, but nothing seems to work. Please let me know if I need to add anything else.

Thank you!

Mykid
  • 13
  • 4

1 Answers1

0

You didn't post your Visualforce page's code.

Even if it's same page (if your apex class is used in ProjectAgreement VF as <apex:page standardController="i360__Quote__c" extensions="attachPDFToQuote" - the act of grabbing a PDF version of the page counts as callout, a separate http traffic to fresh instance of the page so to speak.

So I suspect you need something like

PageReference pdfPage = Page.ProjectAgreement;
pdfPage.getParameters().put('id', q.Id);
Blob = pdfPage.getContent();

If that works... next step would be to look at your VF code.

If the page has merge fields such as {!i360__Quote__c.Name}, {!i360__Quote__c.Correspondence_Name__c} then magic should happen. Salesforce should figure out which fields are needed by looking at your VF page and silently query them for you. So you wouldn't even need the query in your constructor, you could just save stdController.getId() to class variable and then use that id in pdfPage.getParameters().set(...)

But if your VF page has references to {!quote.Correspondence_Name__c} then you need to keep the explicit query in there.

eyescream
  • 18,088
  • 2
  • 34
  • 46
  • Hey eyescream, My VF page for the agreement is very long, which is why I didn't post it originally. The top of the page is referenced as you stated: "" – Mykid Apr 27 '22 at 16:29
  • Here's an example of how I'm using the merge fields in the VF page: " Customer Name: {!i360__Quote__c.Correspondence_Name__c} " (I have the field in there twice to see if either one would print, and they just don't) – Mykid Apr 27 '22 at 16:32
  • I've also encountered something using the code you suggested: "Error: Compile Error: Method does not exist or incorrect signature: void set(String, Id) from the type Map at line 29 column 33" I'm still a beginner, so I can't identify why the error is referencing a "Map". From my perspective, "set" looks like a method, but it may be a way to create a Set collection. I am not sure. – Mykid Apr 27 '22 at 16:36
  • My bad, try with `put`, not `set`. You want something like https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/apex_System_PageReference_getParameters.htm – eyescream Apr 27 '22 at 16:55
  • eyescream, you are a gentleman and a scholar. That little bit of code solved the problem instantly. Thank you so much!! I upvoted, but apparently I'm too new for that to make a difference. Much appreciated! – Mykid Apr 27 '22 at 17:10
  • you can tick it (mark as accepted) so it goes off the radar for other users (and you'll gain a bit of reputation yourself). good luck on your SF journey! have also a look at dedicated https://salesforce.stackexchange.com/ – eyescream Apr 27 '22 at 17:53