Monday, 15 November 2010

Utilizing Visualforce Pages

Ok let’s just get into this….we have completed testing our Apex Triggers and now we are going to use Visualforce pages to fix the display and usability issues we have encountered by creating the presentation page for the Scheduled Invoice object. In case you forgot, in my previous posts I mentioned that Visualforce follows the MVC (Model View Controller) paradigm. Hence the VF pages provide tight integration with the Salesforce database. Visualforce pages are made up of components (custom or already available). These components basically render HTML tags when called from the browser. Once the VF pages are constructed and saved in the Salesforce servers the users can access those pages using URL links in the browser.  When a call is made to the Salesforce servers for those pages, the VF tags are rendered as HTML tags instead and an HTML page is displayed at the browser.
The new page we are creating will display the scheduled payments from the Scheduled Invoice object in three separate lists: ‘Pending’, ‘Past Due’, and ‘Paid’. Payment lists that have no entries (i.e. no past due payments) will be hidden on the page. This will allow us to mark the payment as ‘Paid’ straight from the invoice screen.
The step we are going over in this post is creating the controller class. We are building this class for the Visualforce page to override the standard view of the Scheduled Invoice object. This will the end users to mark payments as paid with a single click and separate payments into groups by status (Pending, Past Due, and Paid). Begin by going to ‘Setup’, then ‘Build’, and finally ‘Code’. This controller class uses the standard Apex Code with methods that are captured from our Visualforce page. Click the ‘New’ button to create the new class and then insert the following code into the body of the class:
public class ScheduledInvoiceControllerExtension
{
    // Store a constant reference to the page's underlying
    // Scheduled_Invoice__c object. The reference is set in
    // the constructor.
    private final Scheduled_Invoice__c cInvoice;
    // Categorized lists of the scheduled payments.
    private List<Scheduled_Payment__c> pastDuePayments =
        new List<Scheduled_Payment__c>();
    private List<Scheduled_Payment__c> pendingPayments =
        new List<Scheduled_Payment__c>();
    private List<Scheduled_Payment__c> paidPayments =
        new List<Scheduled_Payment__c>();
    // This controller is being written as an extension to the
    // standard system controller for the custom object so
    // you can utilize all the standard functionality without
    // having to re-write it. The parameter being passed in
    // is a reference to the standard controller, which you'll
    // use to get a reference to underlying invoice being
    // displayed by the page.
    public ScheduledInvoiceControllerExtension(
        ApexPages.StandardController controller )
    {
        // Get the reference to the current invoice.
        cInvoice = (Scheduled_Invoice__c)controller.getSubject();
        // Load the list of scheduled payments for this invoice.
        loadScheduledPayments();
    }
    // Load the scheduled payments from Salesforce.com and then
    // break them out into categorized lists for use in the page.
    private void loadScheduledPayments()
    {
        List<Scheduled_Payment__c> payments;
        // Load all payments for the current invoice from Salesforce.com.
        // SOQL (Salesforce Object Query Language) statements are wrapped
        // in brackets and can return either an array/list of objects or
        // a single object and variables can be passed into the query by
        // prepending them with a colon.
        payments = [SELECT Id, Name, Status__c, Amount_Due__c,
            Due_Date__c FROM Scheduled_Payment__c
            WHERE Invoice__c = :cInvoice.Id
            ORDER BY Due_Date__c ASC];
        // Split the payment list into categorized list by status.
        for ( Scheduled_Payment__c payment : payments )
        {
            if ( payment.Status__c == 'Pending' )
            {
                pendingPayments.add( payment );
            }
            else if ( payment.Status__c == 'Paid' )
            {
                paidPayments.add( payment );
            }
            else if ( payment.Status__c == 'Past Due' )
            {
                pastDuePayments.add( payment );
            }
        }
    }
    // This method is used by the page to retrieve the pending payments.
    public List<Scheduled_Payment__c> getPendingPayments()
    {
        return pendingPayments;
    }
    // This method is used by the page to retrieve the paid payments.
    public List<Scheduled_Payment__c> getPaidPayments()
    {
        return paidPayments;
    }
    // This method is used by the page to retrieve the past due payments.
    public List<Scheduled_Payment__c> getPastDuePayments()
    {
        return pastDuePayments;
    }
    // This method pulls the parameter paymentId from the
    // the current page and then marks that payment as paid
    // and causes the page to be reloaded.
    // The paymentId parameter is set by the apex:param element
    // of the apex:commandLink element and represents the ID
    // of the payment associated with the row of the commandLink
    // that was clicked to call this method.
    public PageReference markPaymentPaid()
    {
        // Get a reference to the current page.
        PageReference curPage = System.currentPageReference();
        Id paymentId = curPage.getParameters().get( 'paymentId' );
        Scheduled_Payment__c payment;
        // You're creating a new payment object in code, but since
        // you provide it with an ID and then use a database update
        // call it's only updating the existing payment in the
        // database, not creating a new one.
        payment = new Scheduled_Payment__c( Id = paymentId,
            Status__c = 'Paid' );
        Database.update( payment );
        // This creates a new page reference to the invoice you're
        // currently looking at, causing the page to be reloaded
        // when this method returns.
        return new PageReference( '/' + cInvoice.Id );
    }
}
With our controller in place our next course of action is to actually build the page. Once again start by going to ‘Setup’, then ‘Build’, then ‘Page’ and hit ‘New’. Set the label to "Scheduled Invoice View" and the name to "Scheduled_Invoice_View". Finish by replacing the default code with the following:
<!-- When defining the page you can either reference the    -->
<!-- standardController for an object (such as the invoice  -->
<!-- object) or a completely custom controller. If you      -->
<!-- reference the standard controller you can also specify -->
<!-- extensions to that controller, such as the extension   -->
<!-- class.                                                -->
<apex:page standardController="Scheduled_Invoice__c"
  extensions="ScheduledInvoiceControllerExtension" cache="false">
<!-- Here you include the detail section of the object, also      -->
<!-- referred to as the header, without including the related      -->
<!-- lists. This allows you to include insert code between the    -->
<!-- object's header and it's related list sections. That's      -->
<!-- where you'll place the payment lists. The detail section     -->
<!-- of the object will display the object as you have configured -->
<!-- its page layout. Including it in this manner allows this    -->
<!-- page to be maintained primarily from the page layout screen  -->
<!-- rather than having to modify code here.                     -->
  <apex:detail relatedList="false"/>
<!-- The payments form will include three lists of payments -->
<!-- grouped by status.                                   -->
  <apex:form id="paymentsForm">
<!-- This pageBlock section creates a section on the screen that -->
<!-- utilizes Salesforce.com's standard page block look and feel -->
<!-- and uses the custom style you've chosen for your tab.      -->
<!-- Each payment list group is in it's own page block.         -->
    <apex:pageBlock id="pastDueBlock" title="Past Due Payments">
  
<!-- DataTable tags create an HTML table based on data from your   -->
<!-- controller class. The value tag specifies the data that is   -->
<!-- to be retrieved from the controller. The value specified     -->
<!-- below {!PastDuePayments} instructs the page to call the       -->
<!-- getPastDuePayments() method in your controller (or extension) -->
<!-- class. It expects a List or Array as a return value and then -->
<!-- loops through the list creating a row for each entry. The    -->
<!-- var tag is the name to be used for the object containing the  -->
<!-- current row's data and is used by the column elements within  -->
<!-- the table.
<!-- -->
<!-- The CSS styles classes utilized below are predefined          -->
<!-- and more information can be located on the Apex Developer     -->
<!-- network.                                                     -->
      <apex:dataTable width="80%" value="{!PastDuePayments}"
        var="payment" id="pastDueTable" headerClass="headerRow"
        rowClasses="dataRow" styleClass="list">
<!-- This column contains both a facet and a commandLink. The      -->
<!-- facet determines how the column is displayed depending on       -->
<!-- which portion of the table is being rendered. In this case    -->
<!-- the facet provides the display value for the column's header. -->
<!-- -->
<!-- The commandLink in this column displays a link with the label   -->
<!-- "Mark Paid" and executes the markPaymentPaid() method in the    -->
<!-- controller extension. It also contains an apex:param child     -->
<!-- element that sets the page parameter "paymentId" to the Id      -->
<!-- of the scheduled payment object used when rendering the current -->
<!-- row.                                                           -->
        <apex:column>
          <apex:facet name="header"><b>Action</b></apex:facet>
          <apex:commandLink style="font-weight: bold"
            action="{!markPaymentPaid}" value="Mark Paid">
            <apex:param name="paymentId" value="{!payment.Id}"/>
          </apex:commandLink>
        </apex:column>
<!-- The next two columns use an apex:outputField tag to output -->
<!-- properties of the current object for the row when looping  -->
<!-- through the list the table is based on. It also takes     -->
<!-- the display properties of the underlying object's field    -->
<!-- into account when generating the output, using             -->
<!-- localization where necessary.                             -->
        <apex:column>
          <apex:facet name="header"><b>Due Date</b></apex:facet>
          <apex:outputField value="{!payment.Due_Date__c}"/>
        </apex:column>
        <apex:column>
          <apex:facet name="header"><b>Amount Due</b></apex:facet>
          <apex:outputField value="{!payment.Amount_Due__c}"/>
        </apex:column>
      </apex:dataTable>
    </apex:pageBlock>
<!-- This section is the same as the above section, but displays -->
<!-- pending payments only.                                     -->
    <apex:pageBlock id="pendingBlock" title="Pending Payments">
      <apex:dataTable width="80%" value="{!PendingPayments}"
        var="payment" id="pendingTable" headerClass="headerRow"
        rowClasses="dataRow" styleClass="list">
        <apex:column>
          <apex:facet name="header"><b>Action</b></apex:facet>
          <apex:commandLink style="font-weight: bold"
            action="{!markPaymentPaid}" value="Mark Paid">
            <apex:param name="paymentId" value="{!payment.Id}"/>
          </apex:commandLink>
        </apex:column>
        <apex:column>
          <apex:facet name="header"><b>Due Date</b></apex:facet>
          <apex:outputField value="{!payment.Due_Date__c}"/>
        </apex:column>
        <apex:column>
          <apex:facet name="header"><b>Amount Due</b></apex:facet>
          <apex:outputField value="{!payment.Amount_Due__c}"/>
        </apex:column>
      </apex:dataTable>
    </apex:pageBlock>
    
<!-- This section is the same as the above two sections, but -->
<!-- only displays Paid payments and does not have an Action -->
<!-- column since there's no need for it.                   -->
    <apex:pageBlock id="paidBlock" title="Paid Payments">
      <apex:dataTable width="80%" value="{!PaidPayments}"
        var="payment" id="paidTable" headerClass="headerRow"
        rowClasses="dataRow" styleClass="list">
        <apex:column>
          <apex:facet name="header"><b>Due Date</b></apex:facet>
          <apex:outputField value="{!payment.Due_Date__c}"/>
        </apex:column>
        <apex:column>
          <apex:facet name="header"><b>Amount Due</b></apex:facet>
          <apex:outputField value="{!payment.Amount_Due__c}"/>
        </apex:column>
      </apex:dataTable>
    </apex:pageBlock>
  </apex:form>
We will begin the last step of making the page the default display for the  Scheduled Invoice object in the next post.

No comments:

Post a Comment