[SalesForce] Display Total Below the Table in Visualforce page in PDF Format

Can any one help on this .I have creates a visual force page which is in PDF Format.The Scenario is the product name get repeated in different quarters and need to filter by adding its quantity and Amount.I get the Quantities and Amount with the total displayed with the Product Name for all the 4 quarters.Now i would like to get the Subtotals added and displayed.

1)How to get Subtotal and Grand Totals Added and displayed.

PFA Screen Shot:
enter image description here

I get the Table Created as :

ProductName   Q1     Q2     Q3     Q4    Total 
     ABC     100    200   300    400     1000
     PQR     50    150   250    350      800
     XYZ     200    300   400    500     1400
SubTotal       
GrandTotal

But the table should get displayed as :

 ProductName        Q1     Q2     Q3     Q4    Total 
         ABC        100    200   300    400     1000
         PQR        50    150   250    350      800
         XYZ        200    300   400    500     1400
    SubTotal       350    650    950    1250    3200 /Subtotalshouldgetdisplayed
    GrandTotal     350    650    950    1250    3200

Here is Code written but it does not gives the correct value :

    public with sharing class QuoteContentController {
       public Map<String,Decimal> PartMap{get;set;}
 //    public Map<String,Decimal> PartMapQuantity{get;set;}
       public Map<string,Decimal> Quarter1{get;set;}
            public Map<string,Decimal> Quarter2{get;set;}
        public Map<string,Decimal> Quarter3{get;set;}
           public Map<string,Decimal> Quarter4{get;set;}
           public Map<string,Decimal> Amount1{get;set;}
          public Map<string,Decimal> Amount2{get;set;}
           public Map<string,Decimal> Amount3{get;set;}
            public Map<string,Decimal> Amount4{get;set;}
        public Competitor__c com{get;set;}
     public gmod__Opportunity_Forecast__c opflist{get;set;}
    public Id qId {get;set;}
Public string all{get;set;}
   //Declare a wrapper class  
     public class Wrapperclass{
 //custom wrapper datatype  

           Public string Name{get;set;}  
           Public string AccountType{get;set;}  
           Public date todaysDate{get;set;}  
           Public date Expected_Order_Date{get;set;}
           Public string Probability{get;set;}  
           Public string Internal_Comment{get;set;}  
           Public string External_Comment{get;set;}  

           Public string Segment{get;set;}  
           Public string Application{get;set;}  
           Public string Persona{get;set;}  
           Public string Geogrpahy{get;set;}  

           Public string PartNumbers{get;set;}  
           Public Decimal  Price{get;set;}  
           Public Decimal End_Customer_Price{get;set;}  
           Public Decimal Quantity {get;set;}  
           Public Decimal Total{get;set;}  

           Public string RFQ_justification{get;set;}  
           Public string Main_Customer_of_Account{get;set;}  
           Public string Bridgelux_competition_at_account{get;set;}
           Public string Geographic_regions_serviced{get;set;}  
           Public string Annual_lighting_revenue{get;set;}  
           Public string Annual_LED_revenue_or_percent{get;set;}  
           Public string Annual_purchases_of_LED_light_sources{get;set;}
           Public string Percent_of_LED_purchases_that_are_COB{get;set;}  
           Public string Other_information{get;set;}  

           Public string Product_Series{get;set;}  
           Public string Volume{get;set;} 
           Public string Date_Price_is_Valid{get;set;} 

           Public string gmod_Opportunity{get;set;}
           Public string gmod_Product{get;set;}
           Public Decimal gmod_Quantity{get;set;}
           Public Decimal gmod_Price{get;set;}
           Public Decimal gmod_Quarter{get;set;}
           Public Decimal gmod_Month{get;set;}
           Public Decimal gmod_Amount{get;set;}
           Public Decimal Actual_Price{get;set;}
           Public Decimal  gmod_Year{get;set;}
           Public Date gmod_date{get;set;}
           Public string gmod_Month_Text{get;set;}
           Public Date  Forecast_Date{get;set;}
     Public wrapperClass(){} 
   }
     Public QuoteContentController(){}
    Public QuoteContentController(ApexPages.StandardController controller) {
    qId=Apexpages.currentPage().getparameters().get('Id');
     }
    Public Integer subtotalofquantity{get;set;}
    Public Integer subtotalofamount{get;set;}
     Public List<wrapperClass> disp_list {get;set;}{
     subtotalofquantity=0;
    subtotalofamount=0;
      //define constructor to instantiate the wrapper data type 

           disp_list=new list<wrapperclass>();

         //Query all the list 
    list<Quote> q =[select id ,Name ,QuoteNumber,Effective_Date__c ,Comments__c ,Quote.Opportunity.id,Quote.Opportunity.Probability,Quote.Opportunity.AccSegment__c,Quote.Opportunity.AccApplication__c,Quote.Opportunity.Persona__c,Quote.Opportunity.Region__c from Quote where  id=:apexpages.currentpage().getparameters().get('id')];
 Opportunity opp =[select id , Name, (select id, Quantity, product2id from OpportunityLineItems), probability, AccSegment__c from Opportunity where opportunity.Id =:q[0].opportunity.id];
     list<gmod__Opportunity_Forecast__c>  opflist = [Select id ,Name ,gmod__opportunity__r.id,gmod__Product__c,gmod__Quantity__c,gmod__Price__c , gmod__Month__c,    gmod__date__c,  gmod__Quarter__c ,gmod__Amount__c ,Actual_Price__c ,gmod__Year__c ,gmod__Month_Text__c ,Forecast_Date__c,gmod__Product__r.Name ,gmod__opportunity__r.name from gmod__Opportunity_Forecast__c WHERE gmod__Product__c!=null and gmod__opportunity__r.id =:opp.id  order by gmod__Month__c asc ]; 

     //Iterate through each list to extract the values and add it to the custom wrapper data type  
            PartMap = new Map<String,Decimal>();
           //  PartMapQuantity = new Map<String,Decimal>();
              Quarter1 = new Map<String,Decimal>();
            Quarter2 = new Map<String,Decimal>();
             Quarter3 = new Map<String,Decimal>();
             Quarter4 = new Map<String,Decimal>();
            Amount1 = new Map<String,Decimal>();
            Amount2= new Map<String,Decimal>();
            Amount3 = new Map<String,Decimal>();
          Amount4 = new Map<String,Decimal>();
             for(gmod__Opportunity_Forecast__c oppforecast : opflist)
            {
               if(oppforecast .gmod__Month_Text__c=='Jan' || oppforecast .gmod__Month_Text__c=='Feb'|| oppforecast.gmod__Month_Text__c=='Mar')
          {
              if(Quarter1.containskey(oppforecast.gmod__Product__r.Name ))
            {                              Quarter1.put(oppforecast.gmod__Product__r.Name,Quarter1.get(oppforecast.gmod__Product__r.Name) + oppforecast.gmod__Quantity__c);             
                                      Amount1.put(oppforecast.gmod__Product__r.Name,Amount1.get(oppforecast.gmod__Product__r.Name) + oppforecast.gmod__Amount__c);

                                  }
                            else
                                  {

                                     Quarter1.put(oppforecast.gmod__Product__r.Name, oppforecast.gmod__Quantity__c);
                                     Amount1.put(oppforecast.gmod__Product__r.Name,oppforecast.gmod__Amount__c);


                                     wrapperclass w = new wrapperclass();

                                     w.gmod_Opportunity = oppforecast.gmod__Opportunity__r.Name;

                                     w.gmod_Product = oppforecast.gmod__Product__r.Name;

                                     w.gmod_Quantity =oppforecast.gmod__Quantity__c;

                                     w.gmod_Price=oppforecast.gmod__Price__c;

                                     w.Name =oppforecast.Name;

                                     w.gmod_Quarter=oppforecast.gmod__Quarter__c;

                                     w.gmod_Month=oppforecast.gmod__Month__c;

                                     w.gmod_Amount=oppforecast.gmod__Amount__c;

                                     w.Actual_Price=oppforecast.Actual_Price__c;

                                     w.gmod_Year=oppforecast.gmod__Year__c;

                                     w.gmod_date=oppforecast.gmod__date__c;

                                     w.gmod_Month_Text=oppforecast.gmod__Month_Text__c;

                                     w.Forecast_Date=oppforecast.Forecast_Date__c;

                                     disp_list.add(w);
                                } 
                             }

 //   Similarly for other 3 quarter the code repeats as of Quarter 1  


            for (Quote qt :q){
                 System.debug('Quote Size ++ '+q.size());
                 System.debug('opp forcast ++ ' +opflist.size());



                for(integer i=0;i<opflist.size();i++){

                tempsubtotalofquantity+= integer.valueOf(opflist[i].gmod__Quantity__c);

                subtotalofquantity = tempsubtotalofquantity;

                tempsubtotalofamount+= integer.valueOf(opflist[i]. gmod__Amount__c);

                subtotalofamount =tempsubtotalofamount;

               /* subtotalofquantity1+= integer.valueOf(opflist[i].gmod__Quantity__c);

                subtotalofamount1+= integer.valueOf(opflist[i]. gmod__Amount__c);

                subtotalofquantity2+= integer.valueOf(opflist[i].gmod__Quantity__c);

                subtotalofamount2+= integer.valueOf(opflist[i]. gmod__Amount__c);

                subtotalofquantity3+= integer.valueOf(opflist[i].gmod__Quantity__c);

                subtotalofamount3+= integer.valueOf(opflist[i]. gmod__Amount__c); */


                                            //Instantiating the wrapper SObject 

                                            wrapperclass w = new wrapperclass();


                        //Assigning the wrapper variables from the SObject Fields in the database. 

                     w.gmod_Opportunity = opflist[i].gmod__Opportunity__r.Name;

                     w.gmod_Product = opflist[i].gmod__Product__r.Name;

                     w.gmod_Quantity =opflist[i].gmod__Quantity__c;

                     w.gmod_Price=opflist[i].gmod__Price__c;

                     w.Name =opflist[i].Name;

                     w.gmod_Quarter=opflist[i].gmod__Quarter__c;

                     w.gmod_Month=opflist[i].gmod__Month__c;

                     w.gmod_Amount=opflist[i]. gmod__Amount__c;

                     w.Actual_Price=opflist[i].Actual_Price__c;

                     w.gmod_Year=opflist[i].gmod__Year__c;

                     w.gmod_date=opflist[i].gmod__date__c;

                     w.gmod_Month_Text=opflist[i].gmod__Month_Text__c;

                     w.Forecast_Date=opflist[i].Forecast_Date__c; 


                                  //Adding everthing to the List  


                                // w.name =qt.name;

                               //   disp_list.add(w);

                                  // return disp_list;  
    }

    }
                  }       
                  }
             } //End of Class

Visualforce code :

<h3>OpportunityForecast Details</h3>

<table class="bordered">
        <thead>
            <tr>
                <td class="header-table-heading" bgcolor="#C0C0C0" colspan="3"  ></td>
                <td class="header-table-heading" bgcolor="#C0C0C0" colspan="5" >FORECAST DATE</td>
               </tr>
               <tr>              
                <td class="header-table-heading" bgcolor="#C0C0C0">Opportunity Name</td>
                <td class="header-table-heading" bgcolor="#C0C0C0">PartNumbers</td>
                <td class="header-table-heading" bgcolor="#C0C0C0"></td>
                <td class="header-table-heading" bgcolor="#C0C0C0">Q1 2014 </td>
                <td class="header-table-heading" bgcolor="#C0C0C0">Q2 2014 </td>
                <td class="header-table-heading" bgcolor="#C0C0C0">Q3 2014 </td>
                <td class="header-table-heading" bgcolor="#C0C0C0">Q4 2014 </td>
                <!--<td class="header-table-heading" bgcolor="#C0C0C0">Quantity</td>
                <td class="header-table-heading" bgcolor="#C0C0C0">Price</td>
                <td class="header-table-heading" bgcolor="#C0C0C0">Amount</td>
                <td class="header-table-heading" bgcolor="#C0C0C0">Quarter</td>
                <td class="header-table-heading" bgcolor="#C0C0C0">Month</td>
                <td class="header-table-heading" bgcolor="#C0C0C0">Actual Price</td>
                <td class="header-table-heading" bgcolor="#C0C0C0">Year</td>
                <td class="header-table-heading" bgcolor="#C0C0C0">Date</td>-->
               <!-- <td class="header-table-heading" bgcolor="#C0C0C0">MonthText</td>-->
                <!--<td class="header-table-heading" bgcolor="#C0C0C0">ForecastDate</td>
                <td class="header-table-heading" bgcolor="#C0C0C0">ForecastName</td>-->
                <td rowspan="0" class="header-table-heading">Grand<br/>Total </td> 
              </tr>
         </thead>
        <tbody>
           <apex:repeat value="{!disp_list}" var="opf">
            <tr>

                <td class="header-table-data"><apex:outputText value="{!opf.gmod_Opportunity}"/></td>
                <td class="header-table-data"><apex:outputText value="{!opf.gmod_Product}"/></td>
                <td class="header-table-data" >Forecast Qty<br/>ForecastAmt<br/></td>
                <td class="header-table-data"><apex:outputText value="{!Quarter1[opf.gmod_Product]}"/><br/><apex:outputText value="{!Amount1[opf.gmod_Product]}"/><br/></td>
                <td class="header-table-data"><apex:outputText value="{!Quarter2[opf.gmod_Product]}"/><br/><apex:outputText value="{!Amount2[opf.gmod_Product]}"/><br/></td>
                <td class="header-table-data"><apex:outputText value="{!Quarter3[opf.gmod_Product]}"/><br/><apex:outputText value="{!Amount3[opf.gmod_Product]}"/><br/></td>
                <td class="header-table-data"><apex:outputText value="{!Quarter4[opf.gmod_Product]}"/><br/><apex:outputText value="{!Amount4[opf.gmod_Product]}"/><br/></td>
                <!--<td class="header-table-data"><apex:outputText value="{!opf.gmod_Quantity }"/></td>
                <td class="header-table-data"><apex:outputText value="{!opf.gmod_Price }"/></td>
                <td class="header-table-data"><apex:outputText value="{!opf.gmod_Amount }"/></td>
                <td class="header-table-data"><apex:outputText value="{!opf.gmod_Quarter }"/></td>
                <td class="header-table-data"><apex:outputText value="{!opf.gmod_Month }"/></td>
                <td class="header-table-data"><apex:outputText value="{!opf.Actual_Price }"/></td>
                <td class="header-table-data"><apex:outputText value="{!opf.gmod_Year }"/></td>
                <td class="header-table-data"><apex:outputText value="{!opf.gmod_date }"/></td> -->
               <!-- <td class="header-table-data"><apex:outputText value="{!opf.gmod_Month_Text }"/></td> -->
                <!--<td class="header-table-data"><apex:outputText value="{!opf.Forecast_Date }"/></td>
                <td class="header-table-data"><apex:outputText value="{!opf.Name }"/></td>-->
               <!-- <td rowspan="1" style="text-align:left" align="right" class="header-table-heading"> {!subtotalofquantity }<br/>

                     {!subtotalofAmount}<br/></td>-->
                <td class="header-table-data"><apex:outputText value="{!Quarter1[opf.gmod_Product]+Quarter2[opf.gmod_Product]+Quarter3[opf.gmod_Product]+Quarter4[opf.gmod_Product]}"/><br/><apex:outputText value="{!Amount1[opf.gmod_Product]+Amount2[opf.gmod_Product]+Amount3[opf.gmod_Product]+Amount4[opf.gmod_Product]}"/><br/></td>



             </tr>
           </apex:repeat> 
       </tbody>
       <tfoot>
                   <tr class="foot">

                        <tr>

                     <td colspan="2" style="text-align:left" align="right" class="header-table-data" >SubTotal :</td>
                     <td colspan="0"  class="header-table-data"  >Forecast Qty<br/>ForecastAmt<br/> </td>
                     <td colspan="1"  class="header-table-data"><!--<apex:outputText value="{!Quarter1[opf.gmod_Product]+Quarter1[opf.gmod_Product]+Quarter1[opf.gmod_Product]}"/>-->{!subtotalofQuantity}<br/>

                     {!subtotalofAmount }<br/></td>


                    <!--<td colspan="1" style="text-align:left" align="right" class="header-table-data"> <apex:outputText value="{!Quarter1[opf.gmod_Product]}"/><br/>

                     <apex:outputText value="{!Amount1[opf.gmod_Product]}"/><br/></td>-->
                    <!-- <td class="header-table-data"  colspan="1" ><apex:outputText value="{!Quarter1[opf.gmod_Product]+Quarter2[opf.gmod_Product]+Quarter3[opf.gmod_Product]+Quarter4[opf.gmod_Product]}"/><br/><apex:outputText value="{!Amount1[opf.gmod_Product]+Amount2[opf.gmod_Product]+Amount3[opf.gmod_Product]+Amount4[opf.gmod_Product]}"/><br/></td>-->

                    <td colspan="1"  class="header-table-data"> {!subtotalofquantity }<br/>

                     {!subtotalofAmount }<br/></td>
                     <td colspan="1"  class="header-table-data"> {!subtotalofquantity }<br/>

                     {!subtotalofAmount }<br/></td>
                     <td colspan="1"  class="header-table-data"> {!subtotalofquantity }<br/>

                     {!subtotalofAmount }<br/></td>
                     <td colspan="1"  class="header-table-data"> {!subtotalofquantity }<br/>

                     {!subtotalofAmount }<br/></td>

                     </tr> 
                         <tr>

                       <td colspan="2" style="text-align:left"  align="right" class="header-table-heading">GrandTotal</td>
                       <td colspan="0"  class="header-table-heading"  >Forecast Qty<br/>ForecastAmt<br/> </td>
                       <td colspan="1"   class="header-table-heading"> {!subtotalofquantity }<br/>

                     {!subtotalofAmount }<br/></td>
                      <td colspan="1"  class="header-table-heading"> {!subtotalofquantity }<br/>

                     {!subtotalofAmount }<br/></td>
                     <td colspan="1"  class="header-table-heading"> {!subtotalofquantity }<br/>

                     {!subtotalofAmount }<br/></td>
                     <td colspan="1"  class="header-table-heading"> {!subtotalofquantity }<br/>

                     {!subtotalofAmount }<br/></td>

                      <td colspan="1"  class="header-table-heading"> {!subtotalofquantity }<br/>

                     {!subtotalofAmount }<br/></td>

                       </tr> 

                   </tr>

               </tfoot> 
              <!-- </apex:repeat> 
                </tbody> -->

                  </table>

Any help is very much appreciated.

Best Answer

Normally, your wrapper class would be written very similar to as though you'd just run an aggregate query where you had grouped the results and also created Grand Totals. Rather than trying to write your code for you, I'm going to show you the pattern and let you work it out from there. That's how you'll also benefit the most from this answer.

First, let me say that your getters and setters concern me. In particular, you should not need the following:

Public Integer subtotalofquantity{get;set;}
Public Integer subtotalofamount{get;set;}

These should be part of your wrapper and if anything, you'd only be setting their values, not be getting them too. Similar could be said of your data type declarations for getters and setters, but your situation is unique compared to what I'm used to working with in that you're collecting using a query from the standard controller and returning it rather than creating a custom aggregate query. However, you're only setting it through the wrapper class and you're assigning the values to those variable through getters obtained using values from other public variables. Thus, you shouldn't need getters for your wrapper class variables.

You may want to consider rewriting this as an aggregate query to directly obtain the desired results you need. It will save you from "jumping through hoops to get what you need".

Regardless, here's the pattern I suggest you be thinking about that mimics what an aggregrate query would return when you assemble your wrapper class:

For loop: sub.subTotals
          sub.GrandTotals (they're on same level and repeat at same frequency as subtotals, so "sub" can be use to reference both of them as shown in your example table of what you're asking for)
    For loop: opq.fieldsnames (opq represents each quarter)    

Now, when you apply your wrapper class to your VF page, you'll need to set up the following repeats and output texts in your table:

<apex:repeat value="{!disp_list}" var="opf"> (your wrapper list var)
<apex:repeat value="{!opq.opf}" var="opq"> (your wrapper list var by quarter)
   <apex:outputText value="{!opq.gmod_xxxxxx}"/> (xxxxxx = field name)
   etc....

<apex:repeat value="{!opf.sub}" var="ttl">
   <apex:outputText value="{!ttl.subtotalofquantity}"/> 
   etc....
   <apex:outputText value="{!ttl.grandtotalofquantity}"/>
   etc....
</apex:repeat>

</apex:repeat>

That's the general pattern which you'll need to adjust according to your specific needs along with exactly how you create your class and decide to display it on your page. What you don't want to be doing is calculating your sub and grand totals in your visual force page which it appears to me as though you've somehow attempted to do else attempted to pass them directly to the page instead of through your wrapper. Those need to be calculated in your controller and passed to the page within the wrapper class.

Also, I would not put the values in a "footer table class", instead apply a different class to that section of the table if you need to or create a "Head" for your table to hold table row captions of your table. They're not considered the "body" of your table. That's what your data is. I refer you to the following link for more on Table CSS ver 2.1.

EDIT:

I meant to add that there's something which didn't seem quite right to me with the table that you showed for how you want your data to display. Normally, I'd expect each quarter's subtotals to be unique and the different subtotals to accumulate to add to an increasing Grand Total. However, your example table shows each quarter's subtotal being the same as the Grand Total. This makes no sense to me. What it suggests is that you've calculated your quarterly data as cumulative rather than as data for each individual quarter.

The pattern I'd normally have expected and had modified based on what you'd asked for is as follows:

For loop: grn.GrandTotals    
    For loop: sub.subTotals
         For loop: opq.fieldsnames (opq represents each quarter)