Monday, November 3, 2014

Headervalue not displayed in apex column tag

We have observed a strange behavior in headervalue property in <apex:column>tag. Header value won't display value if it is present within <apex:repeat> tags.

We were having a requirement where we need to display opportunity and its related competitor's record in one row. First Column will display opportunity fields and other columns will display field from different competitors related to opportunity. Number of columns will vary based on number of competitors. In order to display dynamic columns, we used <apex:column>  tags within <apex:repeat> tag. There are few fields which are common to opportunity and competitor object. User should be able to edit these fields for opportunity as well as for competitor in same page.

Below is sample code

Output:








In order to resolve this, we used Visualforce Dynamic Components. We created pageblocktable in apex and refereed it VF page.

Below is Code sample
Output after using Visualforce Dynamic Components:









Hope this might help you.

For more info on Visualforce Dynamic Components, Check below links:

https://www.salesforce.com/us/developer/docs/pages/Content/pages_dynamic_vf_components_intro.htm
https://developer.salesforce.com/page/Dynamic_Visualforce_Components

Looking forward for everyone's comment and suggestions.


Monday, September 29, 2014

Quote to Cash Certification Overview

Quote-to-Cash Certification, is a free certification program designed for quoting and contracting knowledge. This certification consists of five video modules, followed by an online test to earn certification badge.

You need to register for this course on http://www.apttus.com/certification/ . After registration, you will get access to 5 training videos and study guide which will help you to clear the certification quiz.

In short, Quote to cash is integrated package of below mentioned functionality:
  • Integrated CPQ, contract management & revenue management-
  • Compensation management that incents reps to offer better deals-
  • Echo sign e-Signature for speedy quoting and contract cycles
  • Sync order details to enterprise resource planning (ERP) and Salesforc

Different modules involved:
  • Quote-to-Cash- Introduction and its benefits
  • Introduction to Configure, Price, Quote (CPQ)
  • Minimizing Risk & Maximizing Revenue with Contract Management
  • Getting Real Insight Into Cash with Effective Revenue Management
  • Quote-to-Cash Success on Salesforce1

This training module will give you functional knowledge of Quote to cash process, helps in understanding CPQ and will explain what are challenges customers are facing to close deals faster . It also describe the functionality provide by APTTUS –Quote to cash package in order to deal with all the challenges while proposing deals or closing the deals.

Features which I like the most in Quote to cash:
  • 100% native to Salesforce so need to integrate it with any 3rd party quoting tool.
  • Guide selling: It provide an ability to configure this app in such a way that sales reps can ask question from customer related to their requirement s and interest and system will populate the suggested products
  • Marked as favorites:  Sales reps can specify products or combination of different products as favorites so that they don’t have to search it every time.
  • Ability to configure discounts at account or partner level, quote level and quote line item level.
  • Availability of API’s related to all CPQ functionality so that developers can customize the app based on customer requirements.
  • Ability to configure E-commerce for external customer easily by using Exposed API’s provided by APTTUS.

Friday, September 12, 2014

Using the Force.com CLI

Force.com CLI tool allows you to interact directly with Force.com from your command-line.
Functionality includes exporting metadata and packages created in SFDC to a local directory, browsing data objects, executing SOQL queries, executing APEX code,managing custom objects etc.


Download Force.CLI from https://force-cli.heroku.com/

Download Force.com CLI executable file and store it in some folder. Suppose my folder name is "CLI Demo" present in E: drive.


Now Open Command prompt  and go to CLI Demo Folder and use below commands:
E:\CLI Demo>force version


If you are getting version information then it means CLI is configured correctly. Otherwise if you getting some error, then set system variable by navigating computer->my properties-Advanced system settings->Environment variables. Provide CLI Demo folder location in path variable.


Once Force.com CLI is configured properly, then we can use it to export package created in SFDC to local directory. Follow below steps:
  1. Create a package: Go to SetUp-> Create->Packages. Create a new package and include all elements which you want to export from SFDC.
  2.          Now you can go to command prompt and enter following commands:
             First we need to login to SFDC instance in order to fetch package

        For Production and developer sandbox use
        force login -i=login.salesforce.com  -u=USERNAME  -p=PASSWORD+SECURITYTOKEN
                           or
        force login -u=USERNAME  -p=PASSWORD+SECURITYTOKEN

       For Sandbox
        force login -i=test.salesforce.com -u=USERNAME  -p=PASSWORD+SECURITYTOKEN

            To fetch package details:

      force fetch package PACKAGENAME --unpack

      In our case package name is “ForceCLIDemoPackage” so enter

      fetch package ForceCLIDemoPackage --unpack


Now metadata folder is created in CLI Demo folder which contain all components information present in package. If you open it, you will see package.xml containing all components list.


Note: If you deploy components in SFDC org using Workbench, then Force.com CLI will help you create package.xml file easily. You don’t have to manually create package.xml file. Just create package in your source org and Fetch it with Force.com CLI and the zip all contents (package.xml and all folders present in ForceCLIDemoPackage). After this deploy the zip file using workbench to target org.

Available commands:
   login     Log in to force.com
   logout    Log out from force.com
   logins    List force.com logins used
   active    Show or set the active force.com account
   whoami    Show information about the active account
   sobject   Manage standard & custom objects
   field     Manage sobject fields
   record    Create, modify, or view records
   bulk      Load csv file use Bulk API
   fetch     Export specified artifact(s) to a local directory
   export    Export metadata to a local directory
   fetch     Export specified artifact(s) to a local directory
   import    Import metadata from a local directory
   query     Execute a SOQL statement
   apex      Execute anonymous Apex code
   oauth     Manage ConnectedApp credentials
   version   Display current version
   update    Update to the latest version
   push      Deploy single artifact from a local directory
   password  See password status or reset password
   help      Show this help

Run 'force help [command]' for details.





Tuesday, June 10, 2014

Displaying all submitted records for an approval process along with their status in VF Page

Few days back, I got requirement from one of my friends to list all approval process in Visualforce Page in picklist and when user select any approval process, the system should display all the records which are submitted for approval along with their status.
In order to achieve this, I have created a VF page and used REST API to get list of all approval process present in org. After getting the list of approval process in JSON, I parsed the response and displayed the approval process names in picklist. When user select particular approval process, system will query all processinstances records and then with the help of TargetObjectid, it will fetched the Ojbect name. Then system will match the object name related to approval process with object related to targetobjectid.
If it got matched, then processInstance record will be stored in list and will be displayed to user.

VF Page Snapshot:









Notes:

  • First create remote site setting with Remote Site URL as https://xxx.salesforce.com where xxx domain name like ap1,na1 etc.
  • I tried to filter the number of processInstance records by putting where clause but it didn't work for me. So I queried all processInstance records.
  • We can specify where clause on createddate or lastmodifieddate by giving an option to user to select date range. We can display two more fields as startdate and enddate on VF page and system will display only processinstance records created or modified between these 2 dates.

Looking forward to your comments and suggestions.

Below is VF Page Code:

<apex:page controller="DisplayApprovedRecordsController" action="{!FetchAllApprovalProcess}">
<apex:form >
    <apex:pageblock title="Approval processess List">      
        <apex:pageblocksection columns="3">
            <apex:pageblockSectionItem >
                <apex:outputLabel value="Select" for="apr"></apex:outputLabel>
                <apex:selectList value="{!selectedApprovalProcess}" size="1" id="apr">
                    <apex:selectOptions value="{!ApprovalWrapperList}"></apex:selectOptions>
                    <apex:actionsupport event="onchange" action="{!FindRecords}"/>
                </apex:selectList>
            </apex:pageblockSectionItem>          
        </apex:pageblocksection>      
        <apex:pageblockSection title="Approved Records" columns="1" >
            <apex:pageblockTable value="{!recordList}" var="rec" rendered="{!recordList.size>0}">
                <apex:column headerValue="Name">
                    <apex:outputlink value="/{!rec.TargetObjectId}">{!rec.TargetObject.name}</apex:outputlink>
                </apex:column>              
                <apex:column headerValue="Status">
                    <apex:outputText value="{!rec.status}"></apex:outputText>
                </apex:column>
            </apex:pageblockTable>          
            <apex:outputpanel rendered="{!recordList.size==0}">
                <apex:outputText value="No records to display"></apex:outputText>
            </apex:outputpanel>      
        </apex:pageblockSection>
    </apex:pageblock>
</apex:form>
</apex:page>

Apex Class Code:

public class DisplayApprovedRecordsController {
    public List<ApprovalWrapper> ApprovalProcessList{get;set;}//list to store all approval process
    public String selectedApprovalProcess{get;set;}
    Public list<ProcessInstance> recordList{get;set;} //list to store processInstance records to display on UI

    public List<selectoption> getApprovalWrapperList(){
        List<selectoption> temp=new List<selectoption>();
        temp.add(new selectoption('','--Select--'));
        for(String ap:approvalMap.keyset()){
            temp.add(new selectoption(ap,ap));
        }
        return temp;
    }
    public DisplayApprovedRecordsController (){
        ApprovalProcessList=new List<ApprovalWrapper>();
        recordList=new list<ProcessInstance> ();
    }
    public map<String,ApprovalWrapper> approvalMap=new map<String,ApprovalWrapper>();
    public void FetchAllApprovalProcess(){      
        HttpRequest req = new HttpRequest();
        req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID());
        req.setHeader('Content-Type', 'application/json');
        String domainUrl=URL.getSalesforceBaseUrl().toExternalForm();
        system.debug('********domainUrl:'+domainUrl);
        String endpointUrl=domainUrl+'/services/data/v30.0/process/approvals/';
        req.setEndpoint(endpointUrl);
        req.setMethod('GET');      
        Http h = new Http();
        HttpResponse res = h.send(req);
        system.debug(res.getBody());
        String ss=res.getBody();
        string newjsondata = ss.replace('"object"','"objectName"');
       
        // Parse entire JSON response.
        JSONParser parser = JSON.createParser(newjsondata );
        while (parser.nextToken() != null) {
            // Start at the array of invoices.
            if (parser.getCurrentToken() == JSONToken.START_ARRAY) {
                while (parser.nextToken() != null) {
                    // Advance to the start object marker to
                    //  find next approval process object.
                    if (parser.getCurrentToken() == JSONToken.START_OBJECT) {
                        // Read entire  approval process object
                        ApprovalWrapper apr= (ApprovalWrapper)parser.readValueAs(ApprovalWrapper.class);
                        system.debug('Approval name: ' + apr.name);
                        system.debug('Id: ' + apr.id);
                        ApprovalProcessList.add(apr);
                        // Skip the child start array and start object markers.
                        parser.skipChildren();
                    }
                }
            }
        }
        system.debug('********ApprovalProcessList:'+ApprovalProcessList);
        for(ApprovalWrapper aw:ApprovalProcessList){
            approvalMap.put(aw.name,aw);
        }
}
public Pagereference FindRecords(){
recordList=new list<ProcessInstance> ();
        if(selectedApprovalProcess!=null && selectedApprovalProcess!=''){
            recordList=new list<ProcessInstance> ();
            String queryString='Select Id, TargetObjectId,TargetObject.name, Status From ProcessInstance Limit 10000';
            System.debug('*********queryString:'+queryString);
            List<ProcessInstance> temp=Database.query(queryString);
            ApprovalWrapper aw=new ApprovalWrapper();
            aw=approvalMap.get(selectedApprovalProcess);
            String ObjName=aw.objectName;
            recordList=new List<Processinstance>();
            For(ProcessInstance sb:temp){
                String ObjectName=String.valueof(sb.TargetObjectId.getSObjectType());
                system.debug('****ObjectName:'+ObjectName);
                if(Objectname.equalsignorecase(ObjName)){
                    recordList.add(sb);
                }
            }
            System.debug('*********recordList:'+recordList);
       }
        return null;
    }    
    public class ApprovalWrapper{
        public String description{get;set;}
        public String id{get;set;}
        public String name{get;set;}
        public String objectName{get;set;}
        public Integer sortOrder{get;set;}
    }
}