0

I appear to have a very weird error.

I have a business case where I have a button on an opportunity which generates 2 records (related to that opportunity via master-detail). After those records were created, I need to generate a PDF and attach it to the opportunity. The PDF must contain data from the 2 records created.

Basically my flow is like this:

  1. User clicks the button

the button is linked to a visualforce page with an action in the <apex:page> tag, like this:

<apex:page standardController="Opportunity" extensions="OpportunityActionsExtension" action="{!generateConfirmation}" />
  1. 2 child records are created and attached to the opportunity.

in the action in my extension I do something like this:

public PageReference generateConfirmation()
{
    List<Child_record__c> children = new List<Child_record__c>();
    Child_record__c child1 = new Child_record__c();
    child1.Opportunity__c = this.opportunity.Id;
    child1.Name = "Example 1";
    children.add(child1);
    Child_record__c child2 = new Child_record__c();
    child2.Opportunity__c = this.opportunity.Id;
    child2.Name = "Example 2";
    children.add(child2);
    insert children;

    PageReference pdfPage = new PageReference('/apex/PdfPage');
    pdfPage.getParameters().put('Id', opportunity.Id);

    Attachment attachment = new Attachment();
    attachment.Name = 'Confirmation.pdf';
    attachment.ContentType  = 'application/pdf';
    attachment.ParentId = opportunity.Id;
    attachment.Body = pdfPage.getContentAsPdf();
    insert attachment;

    return new PageReference('/' + opportunity.Id);
}

In the extension of the PdfPage, I want to display the 2 child records that were created earlier, in a list. and I have a getter like this:

public List<Child_record__c> getChildren()
{
    return [SELECT Name FROM Child_record__c];
}

Now the weird thing is, in my PDF, I see outdated records.

The first time I click the button, I don't see any child records, while they were inserted in the database.

The second time I click the button, I see the 2 records in my pdf that were generated the first time I click the button.

The third time I see the 2 records from the first time, and the 2 records from the second time. For some reason I don't see my 2 newly created records, that were inserted in the same context, before the pdf is being generated.

When I put the generating of the PDF in a @future method, then it works, however I would want it to work in the same context, else the users must refresh the page. Anyone has something similar, or knows what the cause of this could be?

2 Answers 2

2

The PDF generation takes place in a separate transaction which is therefore isolated from the changes made in the current transaction which are not committed until the request that calls generateConfirmation completes.

You can work-around this by making two requests from the browser, the first that invokes generateConfirmation, and the second that generates the PDF (e.g. by using JavaScript).

Or it can be done with an extra Visualforce page and controller without JavaScript:

public PageReference generateConfirmation()
{
    List<Child_record__c> children = new List<Child_record__c>();
    Child_record__c child1 = new Child_record__c();
    child1.Opportunity__c = this.opportunity.Id;
    child1.Name = "Example 1";
    children.add(child1);
    Child_record__c child2 = new Child_record__c();
    child2.Opportunity__c = this.opportunity.Id;
    child2.Name = "Example 2";
    children.add(child2);
    insert children;

    // Extra page
    PageReference pdfGeneration = new PageReference('/apex/PdfGeneration');
    pdfGeneration.getParameters().put('Id', opportunity.Id);
    return pdfGeneration;
}

Extra page: just invokes init method and then forwards to Opportunity page (using apex:page action); never rendered:

<apex:page controller="PdfGenerationController" action="{!init}"/>

Extra page controller: adds the attachment then forwards to the Opportunity page:

public with sharing class PdfGenerationController {

    public PageReference init() {

        String opportunityId = ApexPages.currentPage().getParameters().get('Id');

        PageReference pdfPage = new PageReference('/apex/PdfPage');

        Attachment attachment = new Attachment();
        attachment.Name = 'Confirmation.pdf';
        attachment.ContentType  = 'application/pdf';
        attachment.ParentId = opportunityId;
        attachment.Body = pdfPage.getContentAsPdf();
        insert attachment;

        return new PageReference('/' + opportunityId);
    }
}
3
  • aces, I was thinking about that earlier, but didn't want to start implementing just yet, as it would need quite an overhaul. I'll test it out later and see if everything works as expected.
    – pjcarly
    Oct 20, 2014 at 9:12
  • @PJC It has caused us some pain too in an app that generates documents. We originally went with the above pattern but are now using the future approach for its simplicity. But in our case the documents are typically not used for a while.
    – Keith C
    Oct 20, 2014 at 9:59
  • Cheers man, your solution worked, thanks for the info, it's clear now :)
    – pjcarly
    Oct 20, 2014 at 15:37
0

Just a shot in the dark for the Opportunity ID just in case something happens elsewhere and as far as the records returned being more than 2 this should fix that.

pdfPage.getParameters().put('Id', this.opportunity.Id);

Also, you could ad an action function on the page and a script statement to call the action function that will generate the PDF to see if the breakup of transactions solves the issue.

public List<Child_record__c> getChildren()
{
    return [SELECT Name FROM Child_record__c Order By CreatedDate DESC limit 2];
}

Also, try debugging a query after the insert to see of the records have been propagated yet.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .