Ads

Thursday, 22 August 2013

ISBLANK() or ISNULL() in Salesforce?

To determine if an expression has a value or not, you can use ISBLANK() function in Salesforce. It will  returns TRUE if it does not and if it contains a value, this function returns FALSE. You can use this function in formula field, as well as in workflow.

ISBLANK(expression) and replace expression with the expression you want evaluated.
sample:
IF(ISBLANK(Maint_Amount__c), 0, 1)

A field is not empty if it contains a character, blank space, or zero. For example, a field that contains a space inserted with the spacebar is not empty.

If you use this function with a numeric field, the function only returns the specified string if the field does not have a value and is not configured to treat blank fields as zeroes.

You also can use BLANKVALUE() function to determine if an expression has a value and returns a substitute expression if it does not. If the expression has a value, returns the value of the expression.
sample:
BLANKVALUE(Payment_Due_Date__c, StartDate +5)
Use the same data type for both the expression and substitute_expression.

How about ISNULL() ?
Use ISBLANK instead of ISNULL in new formulas. ISBLANK has the same functionality as ISNULL, but also supports text fields. Salesforce will continue to support ISNULL, so you do not need to change any existing formulas.

The same goes for NULLVALUE(), it is similar with BLANKVALUE(), with exception:

Avoid using NULLVALUE with text fields because they are never null even when they are blank. Instead, use the BLANKVALUE function to determine if a text field is blank.
Don’t use NULLVALUE for date/time fields.

Choose Treat blank fields as blanks for your formula when referencing a number, percent, or currency field. Choosing Treat blank fields as zeroes gives blank fields the value of zero so none of them will be null.

Wednesday, 21 August 2013

How to Customize the Lead Conversion Process in Salesforce.com?

trigger lead_onConvert on Lead (after update) {

/*  Create variables to store the lead values,new and old.  This will be used below to determine if the leads are being converted,  not converted yet, or has already been converted.*/

List<Lead> newLeads = trigger.new;
Map<Id, Lead> mOldLeads = trigger.oldMap;
Lead oldLead;

/* Create sets of Ids to store the records associated with the converted leads */

Set<Id> convertedAccountIds = new Set<Id>();
Set<Id> convertedContactIds = new Set<Id>();
Set<Id> convertedOpportunityIds = new Set<Id>();

/* Loop through the leads submitted through this trigger.  Populate the appropriate sets of Ids for each lead with populated values.*/

for (Lead l : newLeads) {

if (l.convertedAccountId != null) {
convertedAccountIds.add(l.convertedAccountId);
}

if (l.convertedContactId != null) {
convertedContactIds.add(l.convertedContactId);
}

if (l.convertedOpportunityId != null) {
convertedOpportunityIds.add(l.convertedOpportunityId);
}
}

/* Extract the records associated with each set of Ids populated above.  Once the data has been extracted store it in a map so it can efficiently be referenced
 in the main loop below.*/

List<Account> accounts =[SELECT Id, Name FROM Account WHERE Id IN : convertedAccountIds];

Map<Id, Account> mAccounts = new Map<Id, Account>(accounts);

List<Contact> contacts =[SELECT Id, Name FROM Contact WHERE Id IN : convertedContactIds];

Map<Id, Contact> mContacts = new Map<Id, Contact>(contacts);

List<Opportunity> opportunities =[SELECT Id, Name FROM Opportunity WHERE Id IN : convertedOpportunityIds];

Map<Id, Opportunity> mOpportunities = new Map<Id, Opportunity>(opportunities);

/* Create lists of records to be updated in bulk at the end of this trigger.  We use a separate list to ensure we aren't updating records that are  not affected by this trigger. */

List<Account> updateAccounts = new List<Account>();
List<Contact> updateContacts = new List<Contact>();
List<Opportunity> updateOpportunities = new List<Opportunity>();

/*
* MAIN LOOP
*
* Loop through all leads submitted through this trigger.
* If this trigger was executed because of a conversion
* we will populate the related records.
*/
for (Lead newLead : newLeads) {

// Get a reference to the old values associated
// with this lead.
oldLead = mOldLeads.get(newLead.Id);

// Determine if the lead was converted or not.
// If the previous status was not converted and
// the current status is converted, then this
// trigger executed because of a conversion.
if (!oldLead.IsConverted && newLead.isConverted) {

// ** CONVERSION FOUND **

Account account = mAccounts.get(newLead.convertedAccountId);
// Make appropriate updates here.
updateAccounts.add(account);

Contact contact = mContacts.get(newLead.convertedContactId);
// Make appropriate updates here.
updateContacts.add(contact);

Opportunity opportunity = mOpportunities.get(newLead.convertedOpportunityId);
// Make appropriate updates here.
updateOpportunities.add(opportunity);

}
}

/* Update the records for any update list  populated with records.*/

if (updateAccounts.size() > 0) {
update updateAccounts;
}

if (updateContacts.size() > 0) {
update updateContacts;
}

if (updateOpportunities.size() > 0) {
update updateOpportunities;
}
}

How We can get the list of contacts and accounts converted from leads on a particular Date?

We can get the list of contacts and accounts converted from leads on a particular Date

Actually everyone thinks it's impossible to find Solution,But after a lot of research I found a way for this:

Run a Report on Account History/ Contact History with a Specified date and Add the Filter Field/Event set to Created by Lead Covert to find the records that were created upon lead conversion, or set to Lead Converted to Contact to find the records that already exist and merged with lead conversion.




Tuesday, 20 August 2013

Phone Number validation In Salesforce?

Converting 10-Lines of Apex code to a 1-line Validation Rule Formula
Code clean-up is what I'm doing these days ... lots of code clean-up. One of our Salesforce.com orgs (we have sixteen of them) currently has 72% test coverage in production. I'm not sure how the previous administrators were able to install code below the 75% threshold, but they managed. I'm tasked with getting that code cleaned up, so I can deploy a new release.

While looking for areas to improve code coverage, I stumbled upon this trigger:

trigger checkAccountPhoneNumberBiBu on Account (before insert, before update) {
   for (Account account : Trigger.new) {
      if (account.Phone==null) continue;
      Pattern p = Pattern.compile('[-() ]');
      String sPhone = p.matcher(account.Phone).replaceAll('');
      // check length without punctuation
      if (sPhone.length() != 10) account.Phone.addError(' Phone number must have 3 digit area code and 7 digit number');
      p = Pattern.compile('\\d');
      sPhone = p.matcher(sPhone).replaceAll('');
      if (sPhone.length() > 0) account.Phone.addError('Phone number must be formatted as (999)999-9999');
   }
}

This trigger looks at the value entered in the "Phone" field before an Account record is inserted or updated; if the phone field is not in the (999)999-9999 format, it errors out and notifies the user to enter the phone # in the proper format.

In addition to this Apex code, the developer also had to write a testmethod to ensure coverage of the trigger. His code was only getting 67% test coverage (which is what brought the trigger to my attention in the first place).

As I started looking at what I needed to add to the testmethod to ensure 100% coverage, I realized it would be easier to just get rid of the trigger altogether, and replace it with a Validation Rule. That 10 lines of Apex code was reduced to a 1-line formula in a validation rule:

NOT(REGEX(Phone, "\\D*?(\\d\\D*?){10}"))

Standard profiles in Salesforce?


Standard profiles cannot be deleted and permissions cannot be edited.


Thursday, 1 August 2013

Using Rerender to Render — One Solution for Headaches?

It's a regular occurrence to have an <apex:outputPanel> or similar element in a Visualforce page, where you want to toggle visibility of said element according to some variable. Something that's caught both myself and fellow teammates out on a few such occasions is finding that it just won't appear again after being removed from the screen, when the page code looks analogous like the following.

<apex:outputPanel id="thePanel" rendered="{!bRenderThePanel}">
    <!-- Content -->
</apex:outputPanel>

<apex:commandButton action="{!DoSomeCalcs}" rerender="thePanel" value="FIRE!"/>

In this example, the action DoSomeCalcs is implemented such that it will toggle the value of the variable bRenderThePanel and so the result should be that the panel is alternately displayed and hidden with each click of the button. Woe is the developer, as this is not the case. Chances are you'll find yourself confused as to why it just won't reappear (or appear in the first place).

Essentially re-rendering a specified panel (or other component) that is not currently displayed will fail, and the solution is to wrap it with a component that is always present, using that as the target for the re-render. Thus our example becomes:

<apex:outputPanel id="thePanelWrapper">
    <apex:outputPanel rendered="{!bRenderThePanel}">
        <!-- Content -->
    </apex:outputPanel>
</apex:outputPanel>

<apex:commandButton action="{!DoSomeCalcs}" rerender="thePanelWrapper" value="FIRE!"/>

What does seem strange to me is that Salesforce have specifically ensured that you can access DOM elements within an <apex:outputPanel> when it's not displayed, as indicated by the documentation for the layout attribute, it seems odd that this functionality does not carry over for the element itself when it's being used as a re-render target.

The layout style for the panel. Possible values include "block" (which generates an HTML div tag), "inline" (which generates an HTML span tag), and "none" (which does not generate an HTML tag). If not specified, this value defaults to "none". However, if layout is set to "none", for each child element with the rendered attribute set to "false", the outputPanel generates a span tag, with the ID of each child, and a style attribute set to "display:none". Thus, while the content is not visible, JavaScript can still access the elements through the DOM ID.

Happy coding!

Tuesday, 30 July 2013

AggregateResult in Salesforce?

AggregateResult in Salesforce is used to find Sum, Min, Max and Avg. It is similar to Aggregate function in SQL.

Using Aggregate Result, we cannot fetch data. It is mainly used to find Sum, Min, Max and Avg.

Sample Code:

Visualforce page:

<apex:page controller="Sample" sidebar="false" action="{!show}">
<apex:pagemessages />
<apex:form >
    <apex:pageBlock >
        <apex:pageblockTable value="{!SummaryList}" var="r">          
            <apex:column headerValue="Account Name" value="{!r.AcctName}"/>
            <apex:column headerValue="Number of Contacts" value="{!r.Total}"/>
        </apex:pageblockTable>
    </apex:pageBlock>
</apex:form>
</apex:page>

Apex Controller:

public with sharing class Sample {
    public List<AggregateResult> Result {get;set;}  
    public List<Summary> SummaryList {get;set;}
    public List<Account> AcctList;
    public Map<Id, Account> IdAccount;
    List<Id> Ids;
   
    public void show() {
        SummaryList = new List<Summary>();
        Result = new List<AggregateResult>();
        Ids = new List<Id>();
        AcctList = new List<Account>();
        IdAccount = new Map<Id, Account>();
       
        Result = [SELECT Count(Id) Total , AccountId FROM Contact GROUP BY AccountId];              
       
        for(AggregateResult a : Result) {  
            Ids.add((Id)a.get('AccountId'));
        }
       
        AcctList = [SELECT Name FROM Account WHERE Id IN : Ids];
       
        System.debug('Account List' + AcctList);
       
        for(Account a : AcctList) {
            IdAccount.put(a.Id, a);          
        }
       
        System.debug('Ids and Accounts are ' + IdAccount);
               
        for(AggregateResult a : Result) {
            Account TempAcct = new Account();          
            TempAcct = IdAccount.get((Id)(a.get('AccountId')));
            system.debug('Account Name is ' + TempAcct.Name);
            SummaryList.add(new Summary(a, TempAcct.Name));              
        }  
    }
   
    public class Summary {
        public Integer Total {get;set;}
        public String AcctName {get;set;}
       
        public Summary(AggregateResult a, String AccountName) {
            Total =  (Integer)a.get('Total');
            AcctName = AccountName;
        }
    }
}
 output: