3

I have a custom Visualforce email template with a VF component inside it that displays the most recent Comment from an approval process. It is built with the same approach shown in this blog post by Douglas Ayers. I will reproduce the relevant code here.

ApprovalRequestComments.component

<apex:component controller="ApprovalRequestCommentsController" access="global">
    <apex:attribute name="relatedToId" assignTo="{!targetObjectId}" type="String" description="ID of the record whose last approval comments to retrieve"/>
    <apex:outputText value="{!comments}"/>
</apex:component>

ApprovalRequestComments.cls

public class ApprovalRequestCommentsController {

    // ID of the record whose most recent approval process comments to retrieve
    public ID targetObjectId { get; set; }

    public String comments {
        get {
            if ( comments == null ) {
                ProcessInstanceStep lastStep = getLastApprovalStep();
                comments = ( lastStep != null ) ? lastStep.comments : '';
            }
            return comments;
        }
        private set;
    }

    public ApprovalRequestCommentsController() {}

    private ProcessInstanceStep getLastApprovalStep() {
        List<ProcessInstanceStep> steps = new List<ProcessInstanceStep>([
            SELECT Comments
            FROM ProcessInstanceStep
            WHERE ProcessInstance.TargetObjectId = :targetObjectId
            ORDER BY SystemModStamp DESC
            LIMIT 1
        ]);
        return ( steps.size() > 0 ) ? steps[0] : null;
    }

}

MyEmail.email

<messaging:emailTemplate subject="{!relatedTo.CaseNumber}" recipientType="User" relatedToType="Case"> 
    <messaging:htmlEmailBody >
        <html>
            <body>
                <p>Your case was rejected for the following reason(s)</p>
                <p>
                    <c:ApprovalRequestComments relatedToId="{!relatedTo.Id}" />
                </p>                        
            </body>
        </html>
    </messaging:htmlEmailBody>  
</messaging:emailTemplate>

This email gets sent out via an Email Alert as a Final Rejection action to both an internal Salesforce user and to an email address on the Case object. The email gets sent, but the comments appear blank for the recipient whose email is specified in a field on the Case. I've made the Apex controller for the "guest" user (since they don't have a user account) visible to the public profile in the org, but the comments are still not visible. Is there anything I can do to allow these comments to display?

5
  • 1
    did you try making the component controller class without sharing ? did you look at the debug output to see whether the soql came back with any rows?
    – cropredy
    Commented Feb 25, 2020 at 17:34
  • It's difficult to debug, but I've narrowed down the issue to the query in the getLastApprovalStep. No rows get returned when the code runs via email. Is there a permission I might be forgetting that would grant someone access to ProcessInstanceStep? I'm wondering if a better solution may be to write the most recent approval comment to a field on the Case via a trigger.
    – nbrown
    Commented Feb 25, 2020 at 18:13
  • without sharing would be the first place I'd start
    – cropredy
    Commented Feb 25, 2020 at 18:39
  • The controller runs without sharing, no difference.
    – nbrown
    Commented Feb 25, 2020 at 18:53
  • shot-in-dark, try querying ProcessInstanceHistory
    – cropredy
    Commented Feb 25, 2020 at 21:19

1 Answer 1

1

I have tried the above code without sharing and made the function call as public and it worked for me.

Also, please make sure you do not declare any attribute with the same name in VF Component.

public String approvalComments {
        get {
            if ( approvalComments == null ) {
                String lastStepComments = getLastApprovalStepComments();
                approvalComments = ( lastStepComments != null ) ? lastStepComments : 'N/A';
            }
            return approvalComments;
        }
        private set;
    }
public String getLastApprovalStepComments() {
        List<ProcessInstanceStep> steps = new List<ProcessInstanceStep>([
            SELECT Comments FROM ProcessInstanceStep WHERE ProcessInstance.TargetObjectId = :invoiceId ORDER BY SystemModStamp DESC LIMIT 1
        ]);
        return ( steps.size() > 0 ) ? steps[0].comments : null;
    }

You must log in to answer this question.

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