Showing posts with label Button Override. Show all posts
Showing posts with label Button Override. Show all posts

Wednesday, March 18, 2015

Pop Up VisualForce page with Auto Close and Parent Refresh features

Building custom solutions in Salesforce you often need to use pop up window with embedded VisualForce page to support required functionality. You can use "modal dialog box" solution. But generally it's more complicated and required usage of heavy external javascript libraries

Let's say you want to create a custom button in layout to call Visual force page as a popup window. In most cases following two features will make final solution much more efficient and user friendly:

Auto Close the pop up if window lost the focus or click on Cancel button.
Without such feature pop up window will require manual close and new click to the button will create another pop up window. Which is confusing the end user.

Refresh Parent window after click on Save button.
If your Visual force page in pop up should update some date in parent cage (recalculate the field, update related list, etc.) you might want this feature. Without it parent SFDC page will stay AS IS as end user will have to refresh the page manually to see updated results.

Step 1: Create a Visual force page and controller
VF page: PopUpAutoCloseAndRefresh
<!-- 
Version      : 1.0
Company      : WebSolo Inc.
Date         : 03.2015
Description  : VF page "PopUpAutoCloseAndRefresh" 
History      :             
-->
<apex:page controller="PopUpAutoCloseAndRefreshContr" sidebar="false" showHeader="false"  >
    <div id="ch" style="display: none;">{!checkParam}</div>
    <script>
    window.onload = function(){  
        window.onblur = function(){
            window.close();
        }
        if(document.getElementById('ch').innerHTML == "Ok!")
        {
            window.opener.location.href="/{!$CurrentPage.parameters.id}";
            window.top.close();
        }
    }
    </script>
    <p style="font-size: 16px; font-weight: bold; margin-left: 10px">Pop Up Auto Close And Refresh Demo</p>
    <apex:form >
        <apex:pageBlock >
            <apex:pageMessage severity="info" strength="1" summary="{!messsage}" escape="false"/> 
            <apex:commandButton value="Close" action="{!CloseAndRefresh}"/>
        </apex:pageBlock>
    </apex:form>
</apex:page>

APEX Class: PopUpAutoCloseAndRefreshContr
/*
Version      : 1.0
Company      : WebSolo inc.
Date         : 03.2015
Description  : controller for VF page "PopUpAutoCloseAndRefresh"
History      :             
*/
public class PopUpAutoCloseAndRefreshContr{
    public String messsage {get;set;}
    public String checkParam {get;set;}
    public PopUpAutoCloseAndRefreshContr(){
        checkParam = 'not Ok!';
        messsage = 'Please click outside of the pop up window for Auto Close<br/>Please click  Close  to  see how parent window will be refreshed';
    }
    public PageReference CloseAndRefresh(){
        checkParam = 'Ok!';
    return null;
    }
} 

Step 2: Create a custom button (for target object) to call the VF page
Custom Button: CloseAndRefresh
Label: CloseAndRefresh
Object Name : YOUR OBJECT
Name: CloseAndRefresh
Behavior: Execute JavaScript
Display Type: Detail Page Button
OnClick JavaScript:
var url = "/apex/PopUpAutoCloseAndRefresh?id={!Opportunity.Id}"; 
var width = "520"; 
var height = "400"; 
window.open(url, '','scrollbars=no,resizable=no,status=no,toolbar=no,menubar=no, width=' + width + ',height=' + height + ',left=' + ((window.innerWidth - width)/2) + ',top=' + ((window.innerHeight - height)/2) );

Step 3: Add created custom button to layout.

To see how the provided example works in real solution please see out post "Custom Validation For Lead Conversion"

Monday, July 14, 2014

Custom Validation For Lead Conversion

To increase data quality Sales Managers encourage their Sales Representatives to gather as much as possible information about Leads before Conversion it to Contact, Account and Opportunity.

There are multiple techniques to enforce SFDC Users to enter values to all required fields before the Conversion. Let's discuss these techniques with implementation details and all its PROS and CONS.

How to enforce Sales Reps to enter values to required Lead fields before the Conversion.


#1 Make fields required on Lead layout

The most obvious and straight forward solution. But not the best one. Salesforce Lead layout allows Administrator to make some fields required (mandatory). But it's hard for Sales representative to get values for all required fields at once. In most cases Sales person can enter some data initially and then revisit the Lead record to update the rest of the important fields later.

PROS: Easy to implement
CONS: Not convenient for Users. To make any update (edit the Lead) User have to enter values in all required fields at once.

#2 Use a validation rule to fire when Lead is actually converted

Such validation rule will help to make certain fields required before converting the Lead but not require them to be entered when User edits the Lead's record.

Here is example of Validation Rule (could be adjusted to meet particular business requirements)

Rule Name:  Lead_Conversion_Validation

Error Condition Formula:
AND(IsConverted,
OR(
ISBLANK(Email),
ISBLANK(Phone),
ISBLANK(Website),
ISBLANK(TEXT(LeadSource)),
ISBLANK(TEXT(Range_of_Revenues__c)),
ISBLANK(State),
ISBLANK(Street),
ISBLANK(City),
ISBLANK(PostalCode),
ISBLANK(Country)
))

Error Message:
Please fill out following fields before conversion:
- Email
- Phone
- Full Address
- Website
- Range of Revenues
- Lead Source

PROS: Pretty easy to implement
CONS: Still not convenient for Users. The Validation Rule fires ONLY when user hit the Convert button on the Lead page, entered data on Conversion page and clicked Convert button. If something goes wrong (any required field is missed) - user will lose his time and will have to return back to the Lead page to enter missed data. Also Error Message is very general and does not really help the User to identify the missed field(s).

#3 Use workflow to update the Lead's Record Type/Layout when User enters all required for conversion fields

To build this solution you will have to create and support two Lead Record Types and related identical Lead layouts:
 - NotReadyForConversion (default) Lead Record Type and related Lead layout without Convert button
 - ReadyForConversion Record Type and related Lead layout with Convert button

Custom workflow have to check/monitor if all required fields have data.
When the necessary fields are filled out workflow action will update the Lead's Record Type to ReadyForConversion and Users will see the Lead in new layout - with Convert button.

PROS: Allows user to edit the Lead and Convert it only when all required fields are filled out.
CONS: Required two Record Type and two Layouts. Difficult to maintain - especially if you have multiple Leads Record Types/Layouts/User Profiles. Still not convenient for Users. No Error message. User can't see/check out which fields are still missing.

#4 Override the standard 'Convert' button with custom button and related VF page/Controller

SFDC Administrator/Developer can create a new custom 'Convert' button to be used on Lead layout instead of native one. Click to the button will call popup window with custom VF page and Controller to check if all required fields have data (based on particular business requirements).
  • If all required fields are filled out - embedded in VF page JavaScript will auto close the pop up window and redirect User to Conversion page.
  • If any required field(s) not filled out yet - VF page will show User Error message with information about which field(s) have to be entered. By click to Close button / or lose pop up window focus / or in 10 seconds of inactivity - close/auto close pop up window. User still on the Lead page and can enter data in missed field.
PROS: Allows user to edit the Lead and Convert it only when all required fields are filled out. User can easy check out which fields are missing to let them to convert the Lead.
CONS: Required some Force.com development. But final result worth the efforts - Sales Users are happy with the solution which help then save time and meet data quality criteria.

Solution Code Sample: (please contact us if you have questions or want to modify this solution to meet your particular business requirements)

Custom Button

Label: Convert
Object Name: Lead
Name: ConvertCustom
Behavior: Execute JavaScript
Display Type: Detail Page Button
OnClick JavaScript

var url = "/apex/Lead_Conversion_Validation?id={!Lead.Id}";
var width = "350";
var height = "350";
window.open(url, '','scrollbars=no,resizable=no,status=no,toolbar=no,menubar=no, width=' + width + ',height=' + height + ',left=' + ((window.innerWidth - width)/2) + ',top=' + ((window.innerHeight - height)/2) );

Visualforce Page: Lead_Conversion_Validation
<!--
Version        : 1.0
Company        : Websolo Inc. (websolo.ca)
Date           : 07/2014
Update History :
-->
<apex:page standardController="Lead" showHeader="false" sidebar="false" extensions="LeadConversionValidation">
<style>
h2
{
  width: 300% !important;
}
</style>
   <script>
window.onload = function(){
window.onblur = function(){window.close();}
     if(document.getElementById('sd').innerHTML == "")
     {
      var ids = document.getElementById('ids').innerHTML;
      window.opener.location.href="/lead/leadconvert.jsp?retURL=%2F" + ids + "&id=" + ids;
      window.top.close();
     }
     else
     {
         setTimeout(function(){
          window.close();
        }, 10000);   
     }
};
   </script>
      <div id="sd" style="display: none;">{!reft}</div>
      <div id="ids" style="display: none;">{!leadobjid}</div> 
 <apex:pageBlock title="Lead Conversion Validation">
      <apex:pageBlockButtons location="bottom">
       <button onclick="window.close();">Close</button>
     </apex:pageBlockButtons>
      <apex:pageMessage severity="error" strength="1">
          <apex:outputText value="{!error}" escape="false" />
          <apex:outputText value="{!sterrmsg}" escape="false" rendered="{!sterr}"/><br />         
      </apex:pageMessage>
  </apex:pageBlock>
</apex:page>


Apex Class: LeadConversionValidation
(controller - code could be adjusted to meet particular business requirements)
/*
Version        : 1.0
Company        : Websolo Inc. (websolo.ca)
Date           : 07/2014
Update History :
*/
public class LeadConversionValidation
{
    public id leadobjid {get; set;}
    public String error {get; set;}
    public String reft {get; set;}
    public Boolean sterr {get; set;}
    public String sterrmsg {get; set;}
    public LeadConversionValidation(ApexPages.StandardController controller)
    {
      sterr = false;
      sterrmsg = 'To convert Lead please change Lead Status to Contacted';
      error = 'Please fill out following fields before conversion:<br />';
      reft = '';
      leadobjid = ((Lead) controller.getRecord()).id;
      Lead leadobj = [select Status, LastName, Keywords__c, Financing_Notes__c, Email,Phone,Website,Employees__c,Rapport__c,LeadSource,Range_of_Revenues__c,State,Street,City,PostalCode,Country from Lead where id =: leadobjid ];
      if(leadobj.LastName == null ||
        leadobj.Keywords__c  == null ||
        leadobj.Financing_Notes__c == null ||
        leadobj.Email == null ||
        leadobj.Phone == null ||
        leadobj.Website == null ||
        leadobj.Employees__c == null ||
        leadobj.Rapport__c == null ||
        leadobj.LeadSource == null ||
        leadobj.Range_of_Revenues__c == null ||
        leadobj.State == null ||
        leadobj.Street == null ||
        leadobj.City == null ||
        leadobj.PostalCode == null ||
        leadobj.Country == null)
        { 
          reft = '1';
          if(leadobj.Keywords__c  == null){error = error + '- Keywords<br />';}
          if(leadobj.Financing_Notes__c  == null){error = error + '- Call Notes (at least 100 characters)<br />';}
          if(leadobj.Email == null){error = error + '- Email<br />';}
          if(leadobj.Phone == null){error = error + '- Phone<br />';}
          if(leadobj.Website == null){error = error + '- Website<br />';}
          if(leadobj.Employees__c  == null){error = error + '- Employees Range<br />';}
          if(leadobj.Rapport__c == null){error = error + '- Rapport<br />';}
          if(leadobj.LeadSource == null){error = error + '- Lead Source<br />';}
          if(leadobj.LastName == null){error = error + '- Lead Name<br />';}
          if(leadobj.Range_of_Revenues__c == null){error = error + '- Range of Revenues<br />';}
          if(leadobj.State == null || leadobj.Street == null || leadobj.City == null || leadobj.PostalCode == null || leadobj.Country == null){error = error + '- Full Address<br />';}     
        }
        if(leadobj.Status != 'Contacted')
        {
          //sterr = true;
          if(reft == '1')
          {
           sterr = true;
          }
          else
          {
           error = '';
           reft = '1';
           sterr = true;
          }
        }         
    }
}


Apex Class: TestLeadConversionValidation (test coverage)
Version        : 1.0
Company        : Websolo Inc. (websolo.ca)
Date           : 07/2014
Update History :
*/
@isTest
private class TestLeadConversionValidation
{
static testMethod void myUnitTest() 
{
Lead ld = new Lead();
ld.LastName = 'test';
ld.Company = 'test';
ld.Email = 'test@test.com';
ld.Phone = '1112223456';
insert ld;
LeadConversionValidation obj = new LeadConversionValidation(new ApexPages.StandardController(ld));
}
}