• Greg M
  • NEWBIE
  • 10 Points
  • Member since 2020

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 4
    Questions
  • 2
    Replies

Hello all, I am having issues trying to rerender data on my VF page. My VF page has a place to enter a date. It should then use that date in the controller SOQL to filter records by. Then it should refresh the section of the VF page that contains the records using the date entered.  Can someone please help me with this? Thanks.

<apex:page controller="ForecastController" sidebar="false"  tabStyle="Opportunity" docType="html-5.0">
    
    <style>
        
        table {
        border-collapse: collapse;
        width: 100%;
        
        }
        
        th {
        text-align: left;
        padding: 4px;
        width:100px;
        
        }
        
        
        td {
        text-align: left;
        padding: 4px;
        
        }
        
        
        tr:nth-child(even) {background-color: #cccccc;}
        
    </style>
    
    <apex:sectionHeader title="Opportunities" subtitle="Forecast Review" description="Please enter the date below you would like to use for historical data."/>
    
    <apex:form id="searchForm">
        <apex:PageBlock mode="edit">        
            <apex:pageblockSection id="searchBlockSection">
                
                <apex:pageBlockSectionItem id="searchBlockSectionItem">
                    <apex:outputLabel >Enter Date (Format: YYYY-MM-DD)</apex:outputLabel>
                    <apex:panelGroup >
                        <apex:inputtext id="searchDate" value="{!searchDate}" />
                        <strong>
                            <apex:commandButton Id="btnSearch" action="{!search}" rerender="renderBlock" status="status" title="Search" value="Search" >
                            </apex:commandButton>
                        </strong>
                    </apex:panelGroup>
                </apex:pageBlockSectionItem>
            </apex:pageblockSection>
            <apex:actionStatus id="status" startText="Searching... please wait..."/> 
            
            <apex:repeat value="{!forecasts}" var="c" >
                <apex:pageBlock title="Close Date (Forecasted) {!c.month}"  >
                    <apex:repeat value="{!c.territories}" var="t" >
                        <apex:pageBlock title="Territory {!t}" >
                            <!-- access map variables -->
                            <table>
                                <tr> 
                                    <th>Account Name</th>
                                    
                                    <th>Territory Manager</th>
                                    
                                    <th>Stage</th>
                                    
                                    <th>Prev Stage</th>
                                    
                                    <th>AD/RBD Close Date</th>
                                    
                                    <th>Prev AD/RBD Close Date</th>
                                    
                                    <th>Close Date</th>
                                    
                                    <th>Prev Close Date</th>
                                    
                                    <th>Opportunity Name</th>
                                    
                                    <th>Total FS + Modules</th>
                                    
                                    <th>Prev Total FS + Modules</th>
                                    
                                    <th>Total Instr Rev</th>
                                    
                                    <th>Prev Total Instr Rev</th>
                                </tr>
                                
                                <apex:repeat var="opps" value="{!opportunities}" >
                                    <apex:variable var="v" value="" rendered="{!IF(c.month=opps.Close_Month_Forecasted__c && t=opps.Account.Terr_From_Zip__c,true,false)}" id="renderBlock">
                                        <tr>
                                            <td style="width:300px;"> {!opps.Account.Name} </td>
                                            
                                            <td> {!opps.Account.Territory_Manager__c} </td>
                                            
                                            <td>{!opps.StageName}</td>
                                            
                                            <td>
                                                <apex:outputText rendered="{!IF(opps.Opportunity_Snapshots__r.size > 0,true,false)}">
                                                    {!opps.Opportunity_Snapshots__r[0].Stage__c}
                                                </apex:outputText>
                                            </td>
                                            
                                            <td>
                                                <apex:outputText value="{0,date,MM-dd-yyyy}">
                                                    <apex:param value="{!opps.AD_RBD_Forecast_Close_Date__c}"/>
                                                </apex:outputText>
                                            </td>
                                            
                                            <td>   
                                                <apex:outputText value="{0,date,MM-dd-yyyy}" rendered="{!IF(opps.Opportunity_Snapshots__r.size > 0,true,false)}">
                                                    <apex:param value="{!opps.Opportunity_Snapshots__r[0].ADRBD_Forecast_Close_Date__c}" />
                                                </apex:outputText>
                                            </td>
                                            
                                            <td>
                                                <apex:outputText value="{0,date,MM-dd-yyyy}">
                                                    <apex:param value="{!opps.CloseDate}"/>
                                                </apex:outputText>  
                                            </td>
                                            
                                            <td>
                                                <apex:outputText value="{0,date,MM-dd-yyyy}" rendered="{!IF(opps.Opportunity_Snapshots__r.size > 0,true,false)}">
                                                    <apex:param value="{!opps.Opportunity_Snapshots__r[0].Close_Date__c}" />
                                                </apex:outputText>
                                            </td>
                                            
                                            <td style="width:250px;">{!opps.Name}</td>
                                            
                                            <td>{!opps.Total_FS_Modules__c}</td>
                                            
                                            <td>
                                                <apex:outputText rendered="{!IF(opps.Opportunity_Snapshots__r.size > 0,true,false)}">
                                                    {!opps.Opportunity_Snapshots__r[0].Total_FS_Modules__c}
                                                </apex:outputText>
                                            </td>
                                            
                                            <td>
                                                <apex:outputText value="{0,number,currency}">
                                                    <apex:param value="{!opps.Total_Instr_Revenue__c}"/>
                                                </apex:outputText></td>
                                            
                                            <td>
                                                <apex:outputText value="{0,number,currency}" rendered="{!IF(opps.Opportunity_Snapshots__r.size > 0,true,false)}">
                                                    <apex:param value="{!opps.Opportunity_Snapshots__r[0].Total_Instr_Revenue__c}" />
                                                </apex:outputText>
                                            </td>
                                        </tr>
                                    </apex:variable>
                                </apex:repeat> 
                            </table>
                        </apex:pageBlock>
                    </apex:repeat>
                </apex:pageBlock>
            </apex:repeat>
            
        </apex:PageBlock>
    </apex:form>
</apex:page>
 
public class ForecastController {
    public Map<String, Map<String, List<Opportunity>>> values {get;set;}
    public List<ForecastWrapper> forecasts {get;set;}
    public List<Opportunity> notForecasted {get;set;}
    public List<Opportunity> forecasted {get;set;}
    public List<Opportunity> opportunities {get;set;}
    public List<Opportunity> searchResults {get;set;}
    public Date startSearch {get;set;}
    public Date endSearch {get;set;}
    
    
    // Create Constructor
    public ForecastController(){
        // Load all the data into a map
        Map<String, Map<String, List<Opportunity>>> values = new Map<String, Map<String, List<Opportunity>>>();
        
        // queries for opps whose stageName = closed recognized but were not forecasted ***NOTE THERE SHOULD BE FIELDS ADDED TO VF PAGE THAT ASK FOR START & END DATES AND ARE THEN USED IN THIS QUERY WHERE CloseDate >= START DATE & <= END DATE
        notForecasted = [SELECT Id, Name, Account.Name, Account.Territory_Manager__c, StageName, AD_RBD_Forecast_Close_Date__c, CloseDate, Forecastable__c, 
                         Forecasted_Close_Date_30_60_90__c, Owner.Name, RecordType.Name, Total_FS_Modules__c, Total_Instr_Revenue__c, Opp_Safe_ID__c, 
                         Close_Month_Forecasted__c, Account.Terr_From_Zip__c, (Select Id FROM Opportunity_Snapshots__r)
                         FROM Opportunity    
                         WHERE (NOT Name LIKE 'Test')
                         AND (Account.BillingCountryCode = 'US' OR Account.BillingCountryCode = 'CA')
                         AND Forecastable__c = false
                         AND StageName = 'Closed / Recognized'
                         AND CloseDate = THIS_MONTH
                         ORDER BY Account.Name];
        // queries opps for currently forecasted records along with subquery of opportunity_snapshot__c -- This shows opps that are now forecasted along with their snapshots if they were also forecasted on the searchDate **NOTE THIS SHOULD USE THE DATE FROM VF PAGE IN THE SUBQUERY TO FIND THOSE SNAPSHOT RECORDS THAT WERE CREATED ON searchDate. I don't know how to make this work.
        foreCasted =  [SELECT Id, Name, Account.Name, Account.Territory_Manager__c, StageName, AD_RBD_Forecast_Close_Date__c, CloseDate, Forecastable__c, 
                       Forecasted_Close_Date_30_60_90__c, Owner.Name, RecordType.Name, Total_FS_Modules__c, Total_Instr_Revenue__c, Opp_Safe_ID__c, 
                       Close_Month_Forecasted__c, Account.Terr_From_Zip__c, 
                       (Select Id, Account_Name__c, ADRBD_Forecast_Close_Date__c, Close_Date__c, Close_Month_Forecasted__c, Install_Date_Instruments_only__c, Opportunity__c, 
                        Opportunity_Name__c, Opp_Safe_ID__c, Quantity__c, Stage__c, Territory__c, Territory_Manager__c, Total_FS_Modules__c, Total_Instr_Revenue__c, Total_Price__c, CreatedDate 
                       FROM Opportunity_Snapshots__r Where DAY_ONLY(createdDate) >=: startSearch AND DAY_ONLY(createdDate) <=: endSearch)
                       FROM Opportunity    
                       WHERE (NOT Name LIKE 'Test')
                       AND (Account.BillingCountryCode = 'US' OR Account.BillingCountryCode = 'CA')
                       AND Forecastable__c = true
                       AND Forecasted_Close_Date_30_60_90__c <> null
                       ORDER BY Account.Name
                      ];
        
        // Need to query for snapshots that are not included in the foreCasted List but were created on searchDate -- This will show records that were previously forecasted on searchDate but are no longer showing as forecasted.
        
        // add both notForecasted & forecasted Lists to Opportunities List
        Opportunities = new List<Opportunity>(notForecasted);
        Opportunities.addAll(forecasted);
        
        
        // Search through all Opportunities List and get both the Close_Month_Forecasted__c & Account.Terr_From_Zip__c and build Map to display on VFP
        for(Opportunity record: Opportunities) {
            
            Map<String, List<Opportunity>> dateRange = values.get(record.Close_Month_Forecasted__c);
            
            if(dateRange == null) {
                values.put(record.Close_Month_Forecasted__c, dateRange = new Map<String, List<Opportunity>>());
            }
            List<Opportunity> territoryList = dateRange.get(record.Account.Terr_From_Zip__c);
            if(territoryList == null) {
                dateRange.put(record.Account.Terr_From_Zip__c, territoryList = new List<Opportunity>());
            }
            territoryList.add(record);
        }
        
        forecasts = new ForecastWrapper[0];
        
        // Load the "keys" into our specified order
        List<String> months = new List<String>(values.keySet());
        months.sort();
        
        for(String month: months) {
            Map<String, List<Opportunity>> territoryList = values.get(month);
            String[] territories = new List<String>(territoryList.keySet());
            territories.sort();
            
            ForecastWrapper wrap = new ForecastWrapper();
            wrap.month = month;
            wrap.territories = territories;
            forecasts.add(wrap);
        }
    }
    
    
    public Date searchDate {
        get
        { 
            return searchDate;
        }
        set;
    }
    
    public PageReference search(){
        if(SearchResults == null){
            SearchResults = new List<Opportunity>();
        } else {
            SearchResults.Clear();
        }
        Date startSearch = searchDate - 1;
        Date endSearch = searchDate + 1;
        String qry = 'SELECT Id, Name, Account.Name, Account.Territory_Manager__c, StageName, AD_RBD_Forecast_Close_Date__c, CloseDate, Forecastable__c, Forecasted_Close_Date_30_60_90__c, Owner.Name, RecordType.Name, Total_FS_Modules__c, Total_Instr_Revenue__c, Opp_Safe_ID__c, Health_System_Opportunity__c, Close_Month_Forecasted__c, Account.Terr_From_Zip__c,(Select Id, Account_Name__c, ADRBD_Forecast_Close_Date__c, Close_Date__c, Close_Month_Forecasted__c, Install_Date_Instruments_only__c, Opportunity__c, Opportunity_Name__c, Opp_Safe_ID__c, Quantity__c, Stage__c, Territory__c, Territory_Manager__c, Total_FS_Modules__c, Total_Instr_Revenue__c, Total_Price__c, CreatedDate FROM Opportunity_Snapshots__r Where DAY_ONLY(createdDate) >=:' + startSearch + ' AND DAY_ONLY(createdDate) <=:' + endSearch + ') FROM Opportunity WHERE (NOT Name LIKE \'Test\') AND (Account.BillingCountryCode = \'US\' OR Account.BillingCountryCode = \'CA\') AND Forecastable__c = true AND Forecasted_Close_Date_30_60_90__c <> null ORDER BY Account.Name' ;
        SearchResults = Database.query(qry);
        return null;
    }
    
    // Defines Wrapper data types
    public class ForecastWrapper {
        public String month {get;set;}
        public String[] territories {get;set;}
    }
}
  • February 18, 2020
  • Like
  • 0
I am having problems getting the VFP to show opportunities that are filtered. I am looking to recreate a summary report (the reason why isn't important to the question).

I have a string/text field Close_Month_Forecasted__c (close month) and a string/text field Account.Terr_From_Zip__c (territory) field on the opportunity object. I am trying to put/show the opportunity records that match not only the close month but the territory (Account.Terr_From_Zip__c)

Can anyone provide some assistance?
 
public class ForecastController {
public Map<String, Map<String, List<Opportunity>>> values {get;set;}
public List<ForecastWrapper> forecasts { get; set; }

public class ForecastWrapper {
    public String month {get;set;}
    public String[] territories {get;set;}
}

public void load(){

    // Load all the data into a map
    Map<String, Map<String, List<Opportunity>>> values = new Map<String, Map<String, List<Opportunity>>>();

    for(Opportunity record:
        [SELECT Id, Name, Account.Name, Account.Territory_Manager__c, StageName, CloseDate, Forecastable__c, 
         Forecasted_Close_Date_30_60_90__c, Close_Month_Forecasted__c, Account.Terr_From_Zip__c, 
         (Select Id, Account_Name__c, ADRBD_Forecast_Close_Date__c, Close_Date__c, Close_Month_Forecasted__c, Install_Date_Instruments_only__c, Opportunity__c, 
          Opportunity_Name__c, Opp_Safe_ID__c, Quantity__c, Stage__c, Territory__c, Territory_Manager__c, Total_FS_Modules__c, Total_Instr_Revenue__c, Total_Price__c, CreatedDate FROM Opportunity_Snapshots__r)
         FROM Opportunity    
         WHERE (NOT Name LIKE 'Test')
         AND (Account.BillingCountryCode = 'US' OR Account.BillingCountryCode = 'CA')
         AND Forecastable__c = true
         AND Forecasted_Close_Date_30_60_90__c <> null
         ORDER BY Account.Name
        ]) {

            Map<String, List<Opportunity>> dateRange = values.get(record.Close_Month_Forecasted__c);

            if(dateRange == null) {
                values.put(record.Close_Month_Forecasted__c, dateRange = new Map<String, List<Opportunity>>());
            }
            List<Opportunity> territoryList = dateRange.get(record.Account.Terr_From_Zip__c);
            if(territoryList == null) {
                dateRange.put(record.Account.Terr_From_Zip__c, territoryList = new List<Opportunity>());
            }
            territoryList.add(record);
        }

    forecasts = new ForecastWrapper[0];

    // Load the "keys" into our specified order
    String[] months = new List<String>(values.keySet());
    months.sort();

    for(String month: months) {
        Map<String, List<Opportunity>> territoryList = values.get(month);
        String[] territories = new List<String>(territoryList.keySet());
        territories.sort();
        ForecastWrapper wrap = new ForecastWrapper();
        wrap.month = month;
        wrap.territories = territories;
        forecasts.add(wrap);
    }
}
 
<apex:page controller="ForecastController" action="{!load}" sidebar="false"  tabStyle="Opportunity" docType="html-5.0">
    <style>

        table {
        border-collapse: collapse;
        width: 100%;

        }

        th {
        text-align: left;
        padding: 4px;

        }


        td {
        text-align: left;
        padding: 4px;
        <!--border-right: 1px solid black;-->
        }

        tr:nth-child(even) {background-color: #cccccc;}
    </style>

    <apex:sectionHeader title="Opportunities" subtitle="Forecast Review"/>
    <table>
        <tr> 
            <th>Account Name</th>
            <th>Territory</th>
            <th>Territory Manager</th>
            <th>Stage</th>
            <th>Prev Stage</th>
            <th>Opportunity Name</th>
        </tr>
    </table>

    <apex:repeat value="{!forecasts}" var="c" >
        <apex:pageBlock title="Close Date (Forecasted) {!c.month}" >
            <apex:repeat value="{!c.territories}" var="t" >
                <apex:pageBlock title="Territory {!t}" >
                    <!-- access map variables -->
                    <apex:repeat var="opps" value="{!values[c][t]}" >
                        <tr>
                            <td> {!opps.Account.Name} </td>
                            <td>{!opps.Account.Terr_From_Zip__c}</td>
                            <td> {!opps.Account.Territory_Manager__c} </td>
                            <td>{!opps.StageName}</td>
                            <td>
                                <apex:outputText rendered="{!opps.Opportunity_Snapshots__r.size > 0}">
                                    <!-- {!opps.Opportunity_Snapshots__r[0].Stage__c} -->
                                </apex:outputText>
                            </td>
                            <td>{!opps.Name}</td>
                        </tr>
                    </apex:repeat> 
                </apex:pageBlock>
            </apex:repeat>
        </apex:pageBlock>
    </apex:repeat>

</apex:page>

User-added image
  • February 12, 2020
  • Like
  • 0
Can anyone provide insight into what I need to do to prevent my page from displaying Territories that return zero results?

They are currently showing because I made a list and my VF page loops through all “Close Date (Forecasted)” fields  in the list using apex:repeat. Then an inner apex:repeat loops through all territories in the territory list.

The problem is that there are not always opportunities that are in both lists. This causes 
******** CONTROLLER *******

public class ForecastController {
    
    public List<Opportunity> opportunities {get;set;}
    public String[] closeDates {get;set;}
    public String[] terrs {get;set;}
    
    
    public void load(){
        
        Opportunities = [SELECT Id, Name, Account.Name, Account.Territory_Manager__c, StageName, CloseDate, Forecastable__c, 
                         Forecasted_Close_Date_30_60_90__c, Close_Month_Forecasted__c, Account.Terr_From_Zip__c, 
                         (Select Id, Account_Name__c, ADRBD_Forecast_Close_Date__c, Close_Date__c, Close_Month_Forecasted__c, Install_Date_Instruments_only__c, Opportunity__c, 
                          Opportunity_Name__c, Opp_Safe_ID__c, Quantity__c, Stage__c, Territory__c, Territory_Manager__c, Total_FS_Modules__c, Total_Instr_Revenue__c, Total_Price__c, CreatedDate FROM Opportunity_Snapshots__r)
                         FROM Opportunity    
                         WHERE (NOT Name LIKE 'Test')
                         AND (Account.BillingCountryCode = 'US' OR Account.BillingCountryCode = 'CA')
                         AND Forecastable__c = true
                         AND Forecasted_Close_Date_30_60_90__c <> null
                         ORDER BY Account.Name
                        ];
        
        // Creating Set to store unique values
        Set<String> monthSet = new Set<String>();
        Set<String> terrSet = new Set<String>();
        for (Opportunity o : opportunities){
            monthSet.add(o.Close_Month_Forecasted__c);
            terrSet.add(o.Account.Terr_From_Zip__c);
        }
        
        // Converting to List in order to sorth the results alphabetically
        List<String> monthList = new List<String>(monthSet);
        List<String> terrList = new List<String>(terrSet);
        monthList.sort();
        terrList.sort();
        
        
        closeDates = new String[monthList.size()];
        Integer i = 0;
        for(String month : monthList){
            closeDates[i] = month;
            i++;
            
        }
        
        terrs = new String[terrList.size()];
        Integer i2 = 0;
        for(String terr : terrList){
            terrs[i2] = terr;
            i2++;
            
        }
        
    }
    
}




**** VF PAGE ****



<apex:page controller="ForecastController" action="{!load}" sidebar="false"  tabStyle="Opportunity" docType="html-5.0">
    <style>
        table {
        border-collapse: collapse;
        width: 100%;
        
        }
        
        th {
        text-align: left;
        padding: 4px;
        
        }
        
        
        td {
        text-align: left;
        padding: 4px;
        <!-- border-right: 1px solid black; -->
        }
        
        tr:nth-child(even) {background-color: #cccccc;}
    </style>
    
    
    <apex:sectionHeader title="Opportunities" subtitle="Forecast Review"/>
    <apex:repeat value="{!closeDates}" var="c" >
        
        <apex:pageBlock title="Close Date (Forecasted) {!c}" >
            
            <apex:repeat value="{!terrs}" var="t" >
                <apex:pageBlock title="Territory {!t}" >
                    <table>
                        
                        <tr>
                            
                            <th>Account Name</th>
                            
                            <th>Territory</th>
                            
                            <th>Territory Manager</th>
                            
                            <th>Stage</th>
                            
                            <th>Prev Stage</th>
                            
                            <th>Opportunity Name</th>
                           
                        </tr>
                        
                        <apex:repeat var="opps" value="{!opportunities}">
                            
                            <apex:variable var="v" value="" rendered="{!IF(c=opps.Close_Month_Forecasted__c && t=opps.Account.Terr_From_Zip__c,true,false)}">
                                
                                <tr>
                                    
                                    <td> {!opps.Account.Name} </td>
                                    
                                    <td>{!opps.Account.Terr_From_Zip__c}</td>
                                    
                                    <td> {!opps.Account.Territory_Manager__c} </td>
                                    
                                    <td>{!opps.StageName}</td>
                                    
                                    <td>
                                        <apex:outputText rendered="{!IF(opps.Opportunity_Snapshots__r.size > 0,true,false)}">
                                            {!opps.Opportunity_Snapshots__r[0].Stage__c}
                                        </apex:outputText>
                                    </td>
                                    
                                    <td>{!opps.Name}</td>
                                    
                                </tr>
                                
                            </apex:variable>
                            
                        </apex:repeat> 
                        
                    </table>
                </apex:pageBlock>
            </apex:repeat>
        </apex:pageBlock>
        
    </apex:repeat>
    
</apex:page>

User-added image
  • February 06, 2020
  • Like
  • 0
So I found the below code and wanted to modify it to meet my needs. The problem that I have is the records displayed in the apex:repeat do not get put in columns like in a apex:pageBlockTable. Other than that, it works fine. How do I modify the below code in order to get the desired result? Thank you in advance for your help!! 

FYI - I found the code here >>> https://blog.jeffdouglas.com/2011/03/02/dynamically-group-display-query-results/

 
<apex:page controller="DisplaySectionsController" action="{!load}" sidebar="false">
  <apex:sectionHeader title="My Sample Display Page" subtitle="Group by States" 
    description="This page shows how you can dynamically group results by field value."/>

  <apex:repeat value="{!states}" var="state">

    <apex:pageBlock title="{!state}">

      <apex:repeat value="{!accounts}" var="account"> 
 
        <apex:outputPanel rendered="{!IF(state=account.BillingState,true,false)}">
        {!account.Name} - {!account.BillingState}<br/>
        </apex:outputPanel>

      </apex:repeat>

    </apex:pageBlock>

  </apex:repeat>

</apex:page>
  • January 28, 2020
  • Like
  • 0

Hello all, I am having issues trying to rerender data on my VF page. My VF page has a place to enter a date. It should then use that date in the controller SOQL to filter records by. Then it should refresh the section of the VF page that contains the records using the date entered.  Can someone please help me with this? Thanks.

<apex:page controller="ForecastController" sidebar="false"  tabStyle="Opportunity" docType="html-5.0">
    
    <style>
        
        table {
        border-collapse: collapse;
        width: 100%;
        
        }
        
        th {
        text-align: left;
        padding: 4px;
        width:100px;
        
        }
        
        
        td {
        text-align: left;
        padding: 4px;
        
        }
        
        
        tr:nth-child(even) {background-color: #cccccc;}
        
    </style>
    
    <apex:sectionHeader title="Opportunities" subtitle="Forecast Review" description="Please enter the date below you would like to use for historical data."/>
    
    <apex:form id="searchForm">
        <apex:PageBlock mode="edit">        
            <apex:pageblockSection id="searchBlockSection">
                
                <apex:pageBlockSectionItem id="searchBlockSectionItem">
                    <apex:outputLabel >Enter Date (Format: YYYY-MM-DD)</apex:outputLabel>
                    <apex:panelGroup >
                        <apex:inputtext id="searchDate" value="{!searchDate}" />
                        <strong>
                            <apex:commandButton Id="btnSearch" action="{!search}" rerender="renderBlock" status="status" title="Search" value="Search" >
                            </apex:commandButton>
                        </strong>
                    </apex:panelGroup>
                </apex:pageBlockSectionItem>
            </apex:pageblockSection>
            <apex:actionStatus id="status" startText="Searching... please wait..."/> 
            
            <apex:repeat value="{!forecasts}" var="c" >
                <apex:pageBlock title="Close Date (Forecasted) {!c.month}"  >
                    <apex:repeat value="{!c.territories}" var="t" >
                        <apex:pageBlock title="Territory {!t}" >
                            <!-- access map variables -->
                            <table>
                                <tr> 
                                    <th>Account Name</th>
                                    
                                    <th>Territory Manager</th>
                                    
                                    <th>Stage</th>
                                    
                                    <th>Prev Stage</th>
                                    
                                    <th>AD/RBD Close Date</th>
                                    
                                    <th>Prev AD/RBD Close Date</th>
                                    
                                    <th>Close Date</th>
                                    
                                    <th>Prev Close Date</th>
                                    
                                    <th>Opportunity Name</th>
                                    
                                    <th>Total FS + Modules</th>
                                    
                                    <th>Prev Total FS + Modules</th>
                                    
                                    <th>Total Instr Rev</th>
                                    
                                    <th>Prev Total Instr Rev</th>
                                </tr>
                                
                                <apex:repeat var="opps" value="{!opportunities}" >
                                    <apex:variable var="v" value="" rendered="{!IF(c.month=opps.Close_Month_Forecasted__c && t=opps.Account.Terr_From_Zip__c,true,false)}" id="renderBlock">
                                        <tr>
                                            <td style="width:300px;"> {!opps.Account.Name} </td>
                                            
                                            <td> {!opps.Account.Territory_Manager__c} </td>
                                            
                                            <td>{!opps.StageName}</td>
                                            
                                            <td>
                                                <apex:outputText rendered="{!IF(opps.Opportunity_Snapshots__r.size > 0,true,false)}">
                                                    {!opps.Opportunity_Snapshots__r[0].Stage__c}
                                                </apex:outputText>
                                            </td>
                                            
                                            <td>
                                                <apex:outputText value="{0,date,MM-dd-yyyy}">
                                                    <apex:param value="{!opps.AD_RBD_Forecast_Close_Date__c}"/>
                                                </apex:outputText>
                                            </td>
                                            
                                            <td>   
                                                <apex:outputText value="{0,date,MM-dd-yyyy}" rendered="{!IF(opps.Opportunity_Snapshots__r.size > 0,true,false)}">
                                                    <apex:param value="{!opps.Opportunity_Snapshots__r[0].ADRBD_Forecast_Close_Date__c}" />
                                                </apex:outputText>
                                            </td>
                                            
                                            <td>
                                                <apex:outputText value="{0,date,MM-dd-yyyy}">
                                                    <apex:param value="{!opps.CloseDate}"/>
                                                </apex:outputText>  
                                            </td>
                                            
                                            <td>
                                                <apex:outputText value="{0,date,MM-dd-yyyy}" rendered="{!IF(opps.Opportunity_Snapshots__r.size > 0,true,false)}">
                                                    <apex:param value="{!opps.Opportunity_Snapshots__r[0].Close_Date__c}" />
                                                </apex:outputText>
                                            </td>
                                            
                                            <td style="width:250px;">{!opps.Name}</td>
                                            
                                            <td>{!opps.Total_FS_Modules__c}</td>
                                            
                                            <td>
                                                <apex:outputText rendered="{!IF(opps.Opportunity_Snapshots__r.size > 0,true,false)}">
                                                    {!opps.Opportunity_Snapshots__r[0].Total_FS_Modules__c}
                                                </apex:outputText>
                                            </td>
                                            
                                            <td>
                                                <apex:outputText value="{0,number,currency}">
                                                    <apex:param value="{!opps.Total_Instr_Revenue__c}"/>
                                                </apex:outputText></td>
                                            
                                            <td>
                                                <apex:outputText value="{0,number,currency}" rendered="{!IF(opps.Opportunity_Snapshots__r.size > 0,true,false)}">
                                                    <apex:param value="{!opps.Opportunity_Snapshots__r[0].Total_Instr_Revenue__c}" />
                                                </apex:outputText>
                                            </td>
                                        </tr>
                                    </apex:variable>
                                </apex:repeat> 
                            </table>
                        </apex:pageBlock>
                    </apex:repeat>
                </apex:pageBlock>
            </apex:repeat>
            
        </apex:PageBlock>
    </apex:form>
</apex:page>
 
public class ForecastController {
    public Map<String, Map<String, List<Opportunity>>> values {get;set;}
    public List<ForecastWrapper> forecasts {get;set;}
    public List<Opportunity> notForecasted {get;set;}
    public List<Opportunity> forecasted {get;set;}
    public List<Opportunity> opportunities {get;set;}
    public List<Opportunity> searchResults {get;set;}
    public Date startSearch {get;set;}
    public Date endSearch {get;set;}
    
    
    // Create Constructor
    public ForecastController(){
        // Load all the data into a map
        Map<String, Map<String, List<Opportunity>>> values = new Map<String, Map<String, List<Opportunity>>>();
        
        // queries for opps whose stageName = closed recognized but were not forecasted ***NOTE THERE SHOULD BE FIELDS ADDED TO VF PAGE THAT ASK FOR START & END DATES AND ARE THEN USED IN THIS QUERY WHERE CloseDate >= START DATE & <= END DATE
        notForecasted = [SELECT Id, Name, Account.Name, Account.Territory_Manager__c, StageName, AD_RBD_Forecast_Close_Date__c, CloseDate, Forecastable__c, 
                         Forecasted_Close_Date_30_60_90__c, Owner.Name, RecordType.Name, Total_FS_Modules__c, Total_Instr_Revenue__c, Opp_Safe_ID__c, 
                         Close_Month_Forecasted__c, Account.Terr_From_Zip__c, (Select Id FROM Opportunity_Snapshots__r)
                         FROM Opportunity    
                         WHERE (NOT Name LIKE 'Test')
                         AND (Account.BillingCountryCode = 'US' OR Account.BillingCountryCode = 'CA')
                         AND Forecastable__c = false
                         AND StageName = 'Closed / Recognized'
                         AND CloseDate = THIS_MONTH
                         ORDER BY Account.Name];
        // queries opps for currently forecasted records along with subquery of opportunity_snapshot__c -- This shows opps that are now forecasted along with their snapshots if they were also forecasted on the searchDate **NOTE THIS SHOULD USE THE DATE FROM VF PAGE IN THE SUBQUERY TO FIND THOSE SNAPSHOT RECORDS THAT WERE CREATED ON searchDate. I don't know how to make this work.
        foreCasted =  [SELECT Id, Name, Account.Name, Account.Territory_Manager__c, StageName, AD_RBD_Forecast_Close_Date__c, CloseDate, Forecastable__c, 
                       Forecasted_Close_Date_30_60_90__c, Owner.Name, RecordType.Name, Total_FS_Modules__c, Total_Instr_Revenue__c, Opp_Safe_ID__c, 
                       Close_Month_Forecasted__c, Account.Terr_From_Zip__c, 
                       (Select Id, Account_Name__c, ADRBD_Forecast_Close_Date__c, Close_Date__c, Close_Month_Forecasted__c, Install_Date_Instruments_only__c, Opportunity__c, 
                        Opportunity_Name__c, Opp_Safe_ID__c, Quantity__c, Stage__c, Territory__c, Territory_Manager__c, Total_FS_Modules__c, Total_Instr_Revenue__c, Total_Price__c, CreatedDate 
                       FROM Opportunity_Snapshots__r Where DAY_ONLY(createdDate) >=: startSearch AND DAY_ONLY(createdDate) <=: endSearch)
                       FROM Opportunity    
                       WHERE (NOT Name LIKE 'Test')
                       AND (Account.BillingCountryCode = 'US' OR Account.BillingCountryCode = 'CA')
                       AND Forecastable__c = true
                       AND Forecasted_Close_Date_30_60_90__c <> null
                       ORDER BY Account.Name
                      ];
        
        // Need to query for snapshots that are not included in the foreCasted List but were created on searchDate -- This will show records that were previously forecasted on searchDate but are no longer showing as forecasted.
        
        // add both notForecasted & forecasted Lists to Opportunities List
        Opportunities = new List<Opportunity>(notForecasted);
        Opportunities.addAll(forecasted);
        
        
        // Search through all Opportunities List and get both the Close_Month_Forecasted__c & Account.Terr_From_Zip__c and build Map to display on VFP
        for(Opportunity record: Opportunities) {
            
            Map<String, List<Opportunity>> dateRange = values.get(record.Close_Month_Forecasted__c);
            
            if(dateRange == null) {
                values.put(record.Close_Month_Forecasted__c, dateRange = new Map<String, List<Opportunity>>());
            }
            List<Opportunity> territoryList = dateRange.get(record.Account.Terr_From_Zip__c);
            if(territoryList == null) {
                dateRange.put(record.Account.Terr_From_Zip__c, territoryList = new List<Opportunity>());
            }
            territoryList.add(record);
        }
        
        forecasts = new ForecastWrapper[0];
        
        // Load the "keys" into our specified order
        List<String> months = new List<String>(values.keySet());
        months.sort();
        
        for(String month: months) {
            Map<String, List<Opportunity>> territoryList = values.get(month);
            String[] territories = new List<String>(territoryList.keySet());
            territories.sort();
            
            ForecastWrapper wrap = new ForecastWrapper();
            wrap.month = month;
            wrap.territories = territories;
            forecasts.add(wrap);
        }
    }
    
    
    public Date searchDate {
        get
        { 
            return searchDate;
        }
        set;
    }
    
    public PageReference search(){
        if(SearchResults == null){
            SearchResults = new List<Opportunity>();
        } else {
            SearchResults.Clear();
        }
        Date startSearch = searchDate - 1;
        Date endSearch = searchDate + 1;
        String qry = 'SELECT Id, Name, Account.Name, Account.Territory_Manager__c, StageName, AD_RBD_Forecast_Close_Date__c, CloseDate, Forecastable__c, Forecasted_Close_Date_30_60_90__c, Owner.Name, RecordType.Name, Total_FS_Modules__c, Total_Instr_Revenue__c, Opp_Safe_ID__c, Health_System_Opportunity__c, Close_Month_Forecasted__c, Account.Terr_From_Zip__c,(Select Id, Account_Name__c, ADRBD_Forecast_Close_Date__c, Close_Date__c, Close_Month_Forecasted__c, Install_Date_Instruments_only__c, Opportunity__c, Opportunity_Name__c, Opp_Safe_ID__c, Quantity__c, Stage__c, Territory__c, Territory_Manager__c, Total_FS_Modules__c, Total_Instr_Revenue__c, Total_Price__c, CreatedDate FROM Opportunity_Snapshots__r Where DAY_ONLY(createdDate) >=:' + startSearch + ' AND DAY_ONLY(createdDate) <=:' + endSearch + ') FROM Opportunity WHERE (NOT Name LIKE \'Test\') AND (Account.BillingCountryCode = \'US\' OR Account.BillingCountryCode = \'CA\') AND Forecastable__c = true AND Forecasted_Close_Date_30_60_90__c <> null ORDER BY Account.Name' ;
        SearchResults = Database.query(qry);
        return null;
    }
    
    // Defines Wrapper data types
    public class ForecastWrapper {
        public String month {get;set;}
        public String[] territories {get;set;}
    }
}
  • February 18, 2020
  • Like
  • 0
Can anyone provide insight into what I need to do to prevent my page from displaying Territories that return zero results?

They are currently showing because I made a list and my VF page loops through all “Close Date (Forecasted)” fields  in the list using apex:repeat. Then an inner apex:repeat loops through all territories in the territory list.

The problem is that there are not always opportunities that are in both lists. This causes 
******** CONTROLLER *******

public class ForecastController {
    
    public List<Opportunity> opportunities {get;set;}
    public String[] closeDates {get;set;}
    public String[] terrs {get;set;}
    
    
    public void load(){
        
        Opportunities = [SELECT Id, Name, Account.Name, Account.Territory_Manager__c, StageName, CloseDate, Forecastable__c, 
                         Forecasted_Close_Date_30_60_90__c, Close_Month_Forecasted__c, Account.Terr_From_Zip__c, 
                         (Select Id, Account_Name__c, ADRBD_Forecast_Close_Date__c, Close_Date__c, Close_Month_Forecasted__c, Install_Date_Instruments_only__c, Opportunity__c, 
                          Opportunity_Name__c, Opp_Safe_ID__c, Quantity__c, Stage__c, Territory__c, Territory_Manager__c, Total_FS_Modules__c, Total_Instr_Revenue__c, Total_Price__c, CreatedDate FROM Opportunity_Snapshots__r)
                         FROM Opportunity    
                         WHERE (NOT Name LIKE 'Test')
                         AND (Account.BillingCountryCode = 'US' OR Account.BillingCountryCode = 'CA')
                         AND Forecastable__c = true
                         AND Forecasted_Close_Date_30_60_90__c <> null
                         ORDER BY Account.Name
                        ];
        
        // Creating Set to store unique values
        Set<String> monthSet = new Set<String>();
        Set<String> terrSet = new Set<String>();
        for (Opportunity o : opportunities){
            monthSet.add(o.Close_Month_Forecasted__c);
            terrSet.add(o.Account.Terr_From_Zip__c);
        }
        
        // Converting to List in order to sorth the results alphabetically
        List<String> monthList = new List<String>(monthSet);
        List<String> terrList = new List<String>(terrSet);
        monthList.sort();
        terrList.sort();
        
        
        closeDates = new String[monthList.size()];
        Integer i = 0;
        for(String month : monthList){
            closeDates[i] = month;
            i++;
            
        }
        
        terrs = new String[terrList.size()];
        Integer i2 = 0;
        for(String terr : terrList){
            terrs[i2] = terr;
            i2++;
            
        }
        
    }
    
}




**** VF PAGE ****



<apex:page controller="ForecastController" action="{!load}" sidebar="false"  tabStyle="Opportunity" docType="html-5.0">
    <style>
        table {
        border-collapse: collapse;
        width: 100%;
        
        }
        
        th {
        text-align: left;
        padding: 4px;
        
        }
        
        
        td {
        text-align: left;
        padding: 4px;
        <!-- border-right: 1px solid black; -->
        }
        
        tr:nth-child(even) {background-color: #cccccc;}
    </style>
    
    
    <apex:sectionHeader title="Opportunities" subtitle="Forecast Review"/>
    <apex:repeat value="{!closeDates}" var="c" >
        
        <apex:pageBlock title="Close Date (Forecasted) {!c}" >
            
            <apex:repeat value="{!terrs}" var="t" >
                <apex:pageBlock title="Territory {!t}" >
                    <table>
                        
                        <tr>
                            
                            <th>Account Name</th>
                            
                            <th>Territory</th>
                            
                            <th>Territory Manager</th>
                            
                            <th>Stage</th>
                            
                            <th>Prev Stage</th>
                            
                            <th>Opportunity Name</th>
                           
                        </tr>
                        
                        <apex:repeat var="opps" value="{!opportunities}">
                            
                            <apex:variable var="v" value="" rendered="{!IF(c=opps.Close_Month_Forecasted__c && t=opps.Account.Terr_From_Zip__c,true,false)}">
                                
                                <tr>
                                    
                                    <td> {!opps.Account.Name} </td>
                                    
                                    <td>{!opps.Account.Terr_From_Zip__c}</td>
                                    
                                    <td> {!opps.Account.Territory_Manager__c} </td>
                                    
                                    <td>{!opps.StageName}</td>
                                    
                                    <td>
                                        <apex:outputText rendered="{!IF(opps.Opportunity_Snapshots__r.size > 0,true,false)}">
                                            {!opps.Opportunity_Snapshots__r[0].Stage__c}
                                        </apex:outputText>
                                    </td>
                                    
                                    <td>{!opps.Name}</td>
                                    
                                </tr>
                                
                            </apex:variable>
                            
                        </apex:repeat> 
                        
                    </table>
                </apex:pageBlock>
            </apex:repeat>
        </apex:pageBlock>
        
    </apex:repeat>
    
</apex:page>

User-added image
  • February 06, 2020
  • Like
  • 0