2

I have a Visualforce page with a custom controller that presents sales data in a simple table. The users would now like to email that data. So I'm trying to leverage the same controller for both the visualforce page and the email template but I cannot get the parameters to pass into the controller for the email (at least it doesn't appear to be passing in).

This is my Controller. I have a controller for the Visualforce Page that works perfectly fine. Then I added a second controller for the email component. The email piece works perfectly too if I hardcode the accountId. But if I try to pass it in via the email template, it appears to be null as my select statement returns no rows. What am I doing wrong:

public with sharing class SalesReportExtension {
private ApexPages.StandardController controller {get; set;}
public list<tableRow> dollarTable {get; set;}
public list<tableRow> unitTable {get; set;} 
// set First of Year and Prior Month End dates and table header labels
public date foy {get; set;}
public date pme {get; set;}
public string foyLabel {get; set;}
public string oneAgoLabel {get; set;}
public string oneAgoPLabel {get; set;}
public string twoAgoLabel {get; set;}
public string twoAgoPLabel {get; set;}
// set up account and ship to/sold to variables
public Account a {get;set;}
public string accountId {get;set;}
public string accountName {get;set;}        // display at top of page
public set<string> accountIds = new set<string>();      // used to query records
public list<Account> accountNames {get;set;}
public string selectedFilter {get;set;}
public list<selectOption> filterOptions {get; set;}
public string selectedTimeframe {get;set;}
public list<selectOption> timeframeOptions {get; set;}


public SalesReportExtension(ApexPages.StandardController controller) {  // used for the visualforce page
    accountId = System.currentPageReference().getParameters().get('id');
    system.debug('------------------------- on screen version');
    system.debug('------------------------- accountId: ' + accountId);

    accountIds.add(accountId);
    a = [SELECT Id, Name, Ship_To_SAP_ID__c, Sold_To_SAP_ID__c, ShippingCity, ShippingState FROM Account WHERE Id IN :accountIds];
    accountNames = new list<Account>{a};
    accountName = a.Name;

    // setup picklist values
    filterOptions = selectOptions();
    selectedFilter = 'ShipTo';
    timeframeOptions = timeframeOptions();
    selectedTimeframe = 'YTD';
    dollarTable = getDollarTable();
}

public SalesReportExtension() {  // used for the email template
        accountId = '001i000000AbyAI';
        //accountId = ApexPages.CurrentPage().getParameters().get('p3_lkid');
        accountIds.add(accountId);
        a = [SELECT Id, Name, Ship_To_SAP_ID__c, Sold_To_SAP_ID__c, ShippingCity, ShippingState FROM Account WHERE Id IN :accountIds];
        system.debug('------------------------- a: ' + a);
        accountNames = new list<Account>{a};
        accountName = a.Name;
        selectedFilter = 'ShipTo';
        selectedTimeframe = 'YTD';
    } 

public list<tableRow> getDollarTable() {... 

My component (SalesReport) is below. Interestingly enough the {!aId} and {!accountId} both are correctly returned to the page. Those line were added for troubleshooting only.

<apex:component controller="SalesReportExtension" access="global">
<apex:attribute name="value" description="the Account Id"
              type="String" required="required" assignTo="{!accountId}"/>

<p>
Value = {!value}<br/>
accountId = {!accountId}<br/>
</p>

<apex:dataTable value="{!dollarTable}" var="dt" cellpadding="10" border="1" style="width:700px">
                <apex:column headerValue="Material" style="width:200px; text-align:left;">
                    {!dt.label}
                </apex:column>
                <apex:column headerValue="{!foyLabel}" style="text-align:right">
                    <apex:outputText value="${0, number, #,##0.00}">
                    <apex:param value="{!dt.Col1}"/>
                    </apex:outputText>
                </apex:column>
                <apex:column headerValue="{!oneAgoLabel}" style="text-align:right">
                    <apex:outputText value="${0, number, #,##0.00}">
                    <apex:param value="{!dt.Col2}"/>
                    </apex:outputText>
                </apex:column>
                <apex:column headerValue="{!oneAgoPLabel}" style="text-align:right">
                    <apex:outputText value="{0, number, #,##0}%">
                    <apex:param value="{!dt.Col3}"/>
                    </apex:outputText>
                </apex:column>
                <apex:column headerValue="{!twoAgoLabel}" style="text-align:right">
                    <apex:outputText value="${0, number, #,##0.00}">
                    <apex:param value="{!dt.Col4}"/>
                    </apex:outputText>
                </apex:column>
                <apex:column headerValue="{!twoAgoPLabel}" style="text-align:right">
                    <apex:outputText value="{0, number, #,##0}%">
                    <apex:param value="{!dt.Col5}"/>
                    </apex:outputText>
                </apex:column>
</apex:dataTable>

And here is my email template:

<messaging:emailTemplate subject="Sales Report" recipientType="Contact" relatedToType="Account">
<messaging:htmlEmailBody >
    <p>Below is the sales data you requested:</p>
    <c:SalesReport value="{!relatedTo.Id}"/>
    <p>Hope this helps with {!relatedTo.Name}.  If you have any questions just let me know.</p>
</messaging:htmlEmailBody>

This is my the top half of my Visualforce page (this works perfectly). The command button is the last line of this code snippet.

        <apex:pageBlockSection Title="Filter by:" id="filter" columns="4" >
            <apex:selectList value="{!selectedFilter}" multiselect="false" size="1">
                <apex:selectOptions value="{!filterOptions}"/>
                <apex:actionSupport event="onchange"
                                action="{!filterChanged}"
                                rerender="dataDollarTable,dataUnitTable,accountTable"
                                status="queryStatus"/>
            </apex:selectList>
            <apex:selectList value="{!selectedTimeframe}" multiselect="false" size="1">
                <apex:selectOptions value="{!timeframeOptions}"/>
                <apex:actionSupport event="onchange"
                                action="{!filterChanged}"
                                rerender="dataDollarTable,dataUnitTable,accountTable"
                                status="queryStatus"/>
            </apex:selectList>

            <apex:commandButton value="Email Report" action="{!sendEmail}" id="emailButton"/>

Updated comments: It does seem like I might be past getting the variable passed in as my but I can't tell because a Debug log doesn't seem to generate but I'm assuming the fact that I can display the Value and accountId that I am correctly passing them. However, my table of data isn't building yet.

Here's a picture of the visualforce page results (which has always worked):

enter image description here

Here's a picture of the send email template results:

enter image description here

1 Answer 1

1

You have a couple of issues here:

  1. Constructor public SalesReportExtension(ApexPages.StandardController controller) will never be called since you stated this is a custom controller (although I'm not so sure about this given your assertion that the VF page works fine).
  2. When used in a VF Component, the constructor public SalesReportExtension() is called before the setter for the component's assignTo="{!accountId}"

Hence, the SOQL select statement in the constructor public SalesReportExtension() will not have a value for accountId as the list accountIds has only a single null element.

A handy reference is the VF Developer's Guide Order of Execution

Update

What triggers the email template to be rendered? Is it a workflow/approval process w/ email alert? if yes - then the record being triggered will implicitly be bound to relatedToType.

I believe that sending an email from 'Send and Email' button on the Account's related lists will also implicitly bind the account to relatedToType.

If using apex to send the email via some controller action or webservice, then the value of setWhatid(..) does the binding.

When you test/preview in the Email template editor, you have to provide an Account in the popup dialog - this also does the binding.

7
  • So I get what you're saying but how do I fix it so I can get the variable set before that call. I'm looking through the order of execution help but I'm honestly not seeing (or more likely, understanding) the fix.
    – terry
    Commented May 14, 2015 at 1:41
  • i made an update
    – cropredy
    Commented May 14, 2015 at 2:04
  • I have a visualforce page that displays a table of sales data. At the top of that page is a custom button to Send Email. That opens the send email form with a visualforce template with the component. So basically I need to email the render the same table of sales data but do it within an email. Hope that makes sense.
    – terry
    Commented May 14, 2015 at 21:00
  • ah - Pls update your post with the URL used in the custom button plus what the Send Email page looks like when populated
    – cropredy
    Commented May 14, 2015 at 21:41
  • I updated the post last night @crop1645. I really do appreciate your help. I thought this would be a fairly simple request from my client but it's proving to be just far enough outside my skill set to make me stumble. :)
    – terry
    Commented May 15, 2015 at 12:36

You must log in to answer this question.

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