3

I'm able to get all the data by calling the Page.getContentAsPDF() function by selecting all the record from Account object.

Basically, I'm loading the pdf content based on query from page constructor with specific parameter as the condition in my query:

PDF generator page:

...
<thead >
    <tr>
        <td>No.</td>
        <td>Outlet Name</td>
        <td>Entity</td>
        <td>Address</td>
        <td>Nominal</td>
        <td>Minimum Purchase</td>
    </tr>
</thead>

 <tbody>
    <apex:repeat id="repeatdata" var="dt" value="{!selectedProductOutletList}" >
        <tr>
            <td>{!FLOOR(count)}</td>
            <td>{!dt.Outlet__r.Name}</td>
            <td>{!dt.Outlet__r.Account__r.Name}</td>
            <td>{!dt.Address__c}</td>
            <td>{!dt.Voucher_Nominal_DSText__c}</td>
            <td>{!dt.Voucher_Minimum_Purchase_DSText__c}</td>
        </tr>
        <apex:variable var="count" value="{!count+ 1}"/>
    </apex:repeat>
</tbody>
...

PDF generator controller:

public class PDFGeneratorController {
    ...
    public List<Account> selectedProductOutletList{get;set;}

    public PDFGeneratorController() {
        //get all selection based on selectedid parameter, this query not getting updated data although the getContentAsPDF() is running after DML update code
        //selectedIds example: 0012800001BOPGW,0012800001BOPGX,0012800001BOPGY
        String selectedIds = ApexPages.currentPage().getParameters().get('sid');

        String selectedIdsDec = EncodingUtil.urlDecode(selectedIds, 'UTF-8');
        List<String> selectedIdList = selectedIdsDec.split(',');

        DescribeSObjectResult dr = Account.getSObjectType().getDescribe();
        List<String> fieldList = new List<String>(dr.fields.getMap().keySet());
        String fields = String.join(fieldList, ',');
        String qAll = 'SELECT ' + fields + ', Outlet__r.Name, Outlet__r.Account__c, Outlet__r.Account__r.Name, Outlet__r.OwnerId, Outlet__r.Owner.Name, Outlet__r.CreatedDate'
            + ' FROM Account';
        qAll += ' WHERE Id IN :selectedIdList'

        selectedProductOutletList = Database.query(qAll);
    }
    ...
}


But the main problem is, I already make change to the account record and it's not getting reflected in my getContentAsPDF(). Because the order of updating the Account record happens after getContentAsPDF() so the pdf file still showing the old Account data.

The save function

...
public void processSelected() {
    Voucher__c voucherObj = new Voucher__c();
    voucherObj.Name = 'Record name';
    insert voucherObj;

    //this will update the account record
    List<Account> productOutletToUpdatePrice = new List<Account>();
    for (Account productOutletObj : (List<Account>) stdSetControllerProductOutlet.getRecords()) {
        productOutletObj.Price__c = 'Some values that updated from apex class';
        productOutletObj.Minimum_Purchase__c = 'Some values that updated from apex class';
        productOutletToUpdatePrice.add(productOutletObj);
    }
    update productOutletToUpdatePrice;

    //populate urlencoded selected ids
    //I only populate the id here, all the records must be getting updated by above code
    //these id will be passed to pdfpagecontroller to be consumed by query
    List<Account> selectedProductOutletList = (List<Account>) stdSetControllerProductOutlet.getRecords();
    List<String> selectedIdList = new List<String>();
    for (Account accountObj : selectedProductOutletList) {
        selectedIdList.add(accountObj.Id);
    }
    String selectedIds = String.join(selectedIdList, ',');
    String selectedIdsEnc = EncodingUtil.urlEncode(selectedIds, 'UTF-8');

    //generate selected account list pdf from visualforce page
    //[main problem] this pdf page generation not getting the recent update from above code
    PageReference prGenerateSelected = Page.PDFGeneratorPage;
    prGenerateSelected.getParameters().put('sid', selectedIdsEnc);
    prGenerateSelected.setRedirect(true);
    Blob outletListBlob = prGenerateSelected.getContentAsPDF();

    //put generated pdf as attachment
    Attachment outletListAtt = new Attachment();
    outletListAtt.ParentId = voucherObj.Id;
    outletListAtt.ContentType = 'application/pdf';
    outletListAtt.Name = 'Vouchername.pdf';
    outletListAtt.Body = outletListBlob;
    insert outletListAtt;
}
...

So, is there any workaround for make sure the Page.getContentAsPDF() is running after I update the record? I understand that the current page and the PDFGeneratorPage is different context, but I already made change into database level and the page still doesn't show the recent data.

I need to get recent record (that was updated) to be showing in Page.getContentAsPDF()

1 Answer 1

3

This has been answered before but I can't find a good example. The problem is that the getContentAsPdf call does not see the changes made because it runs in a separate transaction and the current transaction only commits at the end of the request which is after that call.

The general solution is to move the getContentAsPdf to after the current transaction by using e.g. an @future method.

Look through these various posts https://salesforce.stackexchange.com/search?q=getContentAsPDF to get a feel for how to do that.

PS

If you need the PDF generating synchronously, you can separate the PDF generation into an extra page (pass it the appropriate Id value) that you go to at the end of the original request (assuming that was the result of a click of some sort):

<apex:page controller="PdfController" action="{!generatePdf}"/>

that just generates the PDF and then returns the PageReference you want to end up at in the end without displaying anything.

Or you can use javaScript to make a second call but that is a bit tricker.

2
  • I cannot make it asynchronous due to the attachment needs to be generated immediately for the next process
    – Rival
    Feb 8, 2019 at 11:51
  • @Rival See the PS.
    – Keith C
    Feb 8, 2019 at 12:03

You must log in to answer this question.

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