Ads

Showing posts with label Triggers. Show all posts
Showing posts with label Triggers. Show all posts

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;
}
}

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}"))

Thursday 16 May 2013

How to create One to One relationship in Salesforce?

In Salesforce, we have One to Many relationship and Many to Many relationship.

To achieve One to One relationship in Salesforce, kindly follow the below steps

Objects: Interest, Employee.
Relationship: Interest is Master and Employee is Detail. 

1. Create a Roll up Summary field on Interest object to find the number of employees(Count).


2. Create a trigger in Employee object to check whether Number Of Employees is equal to one. If it is one, then throw an error, else allow the user to create.

Trigger:

trigger oneToOne on Employee__c (before insert, before update)
{
    for(Employee__c e : trigger.New)
    {
        String empId = e.Interest__c;
        Interest__c i = [SELECT Number_of_employees__c FROM Interest__c WHERE Id =: empId];
        Decimal empStrength = i.Number_Of_Employees__c;
        if(empStrength == 1)
        {
            e.addError('Already an employee has been associated with this interest');
        }
    }
}


Output:

When to use before and after trigger in Salesforce?


Before Trigger:
In case of validation check in the same object.
Insert or update the same object.

After Trigger: 
Insert/Update related object, not the same object.
Notification email.
We cannot use After trigger, if we want to update a record because it causes read only error. This is because after inserting or updating, we cannot update a record.

Tuesday 16 April 2013

Best Practices of Triggers?

Use Set & Map wherever applicable
Code:
// for every OpportunityLineItem record, add its associated price book entry to a set so there are no duplicates.
trigger oppLineTrigger on OpportunityLineItem (before insert) {
Set pricebookIds = new Set();
for (OpportunityLineItem oli : Trigger.new)
pricebookIds.add(oli.pricebookentryid);
// Query the PricebookEntries for their associated product color and place the results in a map of price book entery.
Map entries = new Map( [select product2.color__c from pricebookentry where id in :pbeIds]);
// Now use the map to set the appropriate color on every OpportunityLineItem processed by the trigger.
for (OpportunityLineItem oli : Trigger.new)
oli.color__c = entries.get(oli.pricebookEntryId).product2.color__c;
}
Correlating Records with Query Results in Bulk Triggers
• Use the Trigger.newMap and Trigger.oldMap ID-to-sObject maps to correlate records with query results
trigger oppTrigger on Opportunity (before delete) {
for (Quote__c q : [select opportunity__c from quote__c where opportunity__c in :Trigger.oldMap.keySet()])
{
Trigger.oldMap.get(q.opportunity__c).addError('Cannot delete opportunity with a quote');
}
}

Triggers and Order of Execution?

Triggers and Order of Execution
  When user Save record with insert, update or upsert statement in salesforce.com.
1. Client Side Execution:
  • JavaScript validation
  • Dependent pick list
2. Server side Execution:
  • Loads the original record from the database or initializes the record for an upsert statement.
  • Loads the new record field values from the request and overwrites the old values. If the request came from a standard UI edit page, Salesforce runs system validation to check the record for:
    * Compliance with layout-specific rules
    * Required values at the layout level and field-definition level
    * Valid field formats
    * Maximum field length
   Salesforce does not perform system validation in this step when the request comes from other sources, such as an Apex application or a Web services API call.
  • Executes all before triggers.
  • Runs most system validation steps again, such as verifying that all required fields have a non-null value, and runs any user-defined validation rules. The only system validation that Salesforce does not run a second time (when the request comes from a standard UI edit page) is the enforcement of layout-specific rules.
  • Saves the record to the database, but does not commit yet.
  • Executes all after triggers.
  • Executes assignment rules.
  • Executes auto-response rules.
      ·   Executes workflow rules.
·   If there are workflow field updates, updates the record again.
  • If the record was updated with workflow field updates, fires before and after triggers one more time (and only one more time), in addition to standard validations. Custom validation rules are not run again.
  • Executes escalation rules.
  • If the record contains a roll-up summary field or is part of a cross-object workflow, performs calculations and updates the roll-up summary field in the parent record. Parent record goes through save procedure.
  • If the parent record is updated, and a grand-parent record contains a roll-up summary field or is part of a cross-object workflow, performs calculations and updates the roll-up summary field in the parent record. Grand-parent record goes through save procedure.
  • Executes Criteria Based Sharing evaluation.
  • Commits all DML operations to the database.
  • Executes post-commit logic, such as sending email.
*Note: During a recursive save, Salesforce skips steps 7 through 14.
Additional Considerations

Additional Considerations:
Please note the following when working with triggers:

    * When Enable Validation and Triggers from Lead Convert is selected, if the lead conversion creates an opportunity and the opportunity has Apex before triggers associated with it, the triggers run immediately after the opportunity is created, before the opportunity contact role is created. For more information, see “Customizing Lead Settings” in the Salesforce online help.

   * If you are using before triggers to set Stage and Forecast Category for an opportunity record, the behavior is as follows:
          o If you set Stage and Forecast Category, the opportunity record contains those exact values.
          o If you set Stage but not Forecast Category, the Forecast Category value on the opportunity record defaults to the one associated with trigger Stage.
          o If you reset Stage to a value specified in an API call or incoming from the user interface, the Forecast Category value should also come from the API call or user interface. If no value for Forecast Category is specified and the incoming Stage is different than the trigger Stage, the Forecast Category defaults to the one associated with trigger Stage. If the trigger Stage and incoming Stage are the same, the Forecast Category is not defaulted.

   * If you are cloning an opportunity with products, the following events occur in order:
         1. The parent opportunity is saved according to the list of events shown above.
         2. The opportunity products are saved according to the list of events shown above.
    

Handling Governor Limits through Trigger?

1. Bulkify your code:
Bad Code
trigger accTrggr on Account (before insert, before update) {
//This only handles the first record in the Trigger.new collection
//But if more than one Account initiated this trigger, those additional records
//will not be processed
Account acct = Trigger.new[0];
acct.Description = acct.Name + ':' + acct.BillingState;
}
Correct Code
trigger accTrggr on Account (before insert, before update) {
List accountNames = new List{};
//Loop through all records in the Trigger.new collection
for(Account a: Trigger.new) {
//Concatenate the Name and billingState into the Description field a.Description = a.Name + ':' + a.BillingState;
}}
2. Avoid SOQL Queries inside FOR Loops
Move SOQL queries outside FOR loop
Bad Code
trigger accountTestTrggr on Account (before insert, before update) {
for(Account a: Trigger.new) {
List contacts = [select id, salutation, firstname, lastname, email from Contact where accountId = :a.Id];
for(Contact c: contacts){
c.Description=c.salutation + ' ' + c.firstName + ' ' + c.lastname;
update c;
} } }
Good Code
trigger accountTestTrggr on Account (before insert, before update) {
List accountsWithContacts = [select id, name, (select id, salutation, description, firstname, lastname, email from Contacts) from Account where Id IN :Trigger.newMap.keySet()];
List contactsToUpdate = new List{};
for(Account a: accountsWithContacts){
for(Contact c: a.Contacts){
c.Description=c.salutation + ' ' + c.firstName + ' ' + c.lastname; contactsToUpdate.add(c);
} }
update contactsToUpdate;
}
3. Bulkify your Helper Methods
  • Similar to the Previous One.
  • All Helper Methods should also be handling Bulk records.
  • For Eg: A inside a method should receive a bulk set of inputs, process in bulk and return the List of Records.
4. Using Collections, Streamlining Queries, and Efficient For Loops
Bad Code
trigger accountTrigger on Account (before delete, before insert, before update) {
//This code inefficiently queries the Opportunity object in two seperate queries
List opptysClosedLost = [select id, name, closedate, stagename from Opportunity where accountId IN :Trigger.newMap.keySet() and StageName='Closed - Lost'];
List opptysClosedWon = [select id, name, closedate, stagename from Opportunity where accountId IN :Trigger.newMap.keySet() and StageName='Closed - Won'];
for(Account a : Trigger.new){
//This code inefficiently has two inner FOR loops
//Redundantly processes the List of Opportunity Lost
for(Opportunity o: opptysClosedLost){
if(o.accountid == a.id)
System.debug('Do more logic here...'); }
//Redundantly processes the List of Opportunity Won
for(Opportunity o: opptysClosedWon){
if(o.accountid == a.id) System.debug('Do more logic here...'); } } }
Good Code
trigger accountTrigger on Account (before delete, before insert, before update) {
/*This code queries all related Closed Lost & Closed Won oppor in a single query. */
List accountWithOpptys = [select id, name, (select id, name, closedate, stagename from Opportunities where accountId IN :Trigger.newMap.keySet() and (StageName='Closed - Lost' or StageName = 'Closed - Won')) from Account where Id IN :Trigger.newMap.keySet()];
//Loop through Accounts only once
for(Account a : accountWithOpptys){
//Loop through related Opportunities only once
for(Opportunity o: a.Opportunities){
if(o.StageName == 'Closed - Won'){
System.debug('Opportunity Closed Won...do some more logic here...');
}else if(o.StageName =='Closed - Lost'){
System.debug('Opportunity Closed Lost...do some more logic here...');
} } } }
5. Streamlining Multiple Triggers on the Same Object
  • Many Triggers for a single Object
  • Order of execution cant be defined
  • All Triggers executing in a single transaction will SHARE the governor limits.
  • Add appropriate conditions for trigger executions
  • Handling of Governor Limits across all the triggers
  • If possible, join the triggers
6. Querying Large Data Sets
Bad Code
//A runtime exception is thrown if this query returns 1001 or more records.
Account [] accts = [SELECT id FROM account];
Good Code
// Use this format for efficiency if you are executing DML statements
// within the for loop
for (List accts : [SELECT id, name FROM account WHERE name LIKE 'Acme']) {
// Your code here
update accts;
}
7. Other Best Practices
  • Use of the Limits Apex Methods to Avoid Hitting Governor Limits
  • Limits.getLimitQueries()
  • Limits.getLimitDmlRows()
  • Enable Apex Governor Limit Warning Emails
  • Write Test Methods to Verify Large Datasets

Monday 15 April 2013

Trigger for field update in Salesforce?

The below Apex code is used to update a field(Comments__c) in Member__c Object,

where Marital__Status and Comments__c are fields n Member__c object.

Code:

trigger commentsUpdate on Member__c (before Insert,before update) 

     for(Member__c member : Trigger.new)  
     {      
         if(member.Marital_Status__c != '')    
         {      
             member.Comments__c = member.Marital_Status__c;    
         }       
         else   
         {      
             member.Comments__c = 'No comments';    
         }       
     }  
}

Difference between trigger.new and trigger.old in salesforce?

Trigger.new : Returns a list of the new versions of the sObject records. Note that this sObject list is only available in insert and update triggers, and the records can only be modified in before triggers.

Trigger.old : Returns a list of the old versions of the sObject records. Note that this sObject list is only available in update and delete triggers.

For more info visit the below link

http://www.salesforce.com/us/developer/docs/apexco​de/Content/apex_triggers_context_variables.htm

Trigger.isInsert() and trigger.isUpdate() in salesforce?

trigger memberInviteNotify on Member__c (after insert,after update)
{
    for(Member__c member:trigger.New)
    {
        String[] toAddresses = new String[] {member.E_Mail_Id__c};
        String messageBody;
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        mail.setToAddresses(toAddresses);
    
        //Email invitation
        if(trigger.isInsert)
        {
            mail.setSubject('Welcome to Sweet 16');
            messageBody = 'Hi ' + member.Name + ', Welcome to Sweet 16';
            mail.setHtmlBody(messageBody);
        }
        //Email notification
        if(trigger.isUpdate)
        {
            mail.setSubject('Updates in your details');
            messageBody = 'Hi ' + member.Name + ', Changes have been made to your details. Contact administrator if you are not responisble.';
            mail.setHtmlBody(messageBody);
        }
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
    }
}

Trigger to Warn for Duplicate Attachment Names and Contents in Salesforce?

The below trigger is used to warn the users, if the Filename or Content of  an attachment already exists.

Trigger:

/*    Trigger to Warn for Duplicate Attachment Names and Contents    */
trigger DuplicateAttachment on Attachment (before insert)
{
for(Attachment attachmnt:trigger.New)
{
String sql = 'SELECT Name,Description FROM Attachment';
List<Attachment> attach = Database.Query(sql);

for(Attachment temp:attach)
{
if(temp.Name == attachmnt.Name)
{
attachmnt.Name.addError('Duplicate Name. Filename already exists.');
}
if(temp.Description == attachmnt.Description)
{
String str = 'Similar content already exists in ' + temp.Name;
attachmnt.Description.addError(str);
}
}
}
}

trigger.isInsert and trigger.isUpdate?

trigger.isInsert is true when a new record is created and inserted.

trigger.isUpdate is true when an existing record is modified.

Example:

trigger memberInviteNotify on Member__c (after insert,after update)
{

        if(trigger.isInsert)
        {
        // When a new record is created and inserted, the flow will come here
        ............................
        ............................
        ............................ 
        }
        
        if(trigger.isUpdate)
        {

        // When an existing record is modified, the flow will come here
        ............................
        ............................
        ............................
        }

}

Recursive triggers in Salesforce?

You want to write a trigger that creates a new record as part of its processing logic; however, that record may then cause another trigger to fire, which in turn causes another to fire, and so on. You don't know how to stop that recursion.

     Use a static variable in an Apex class to avoid an infinite loop. Static variables are local to the context of a Web request (or test method during a call to runTests()), so all triggers that fire as a result of a user's action have access to it.

Example:
     Suppose there is a scenario where in one trigger perform update operation, which results in invocation of second trigger and the update operation in second trigger acts as triggering criteria for trigger one.

Solution:

Class:

public class Utility
{
    public static boolean isFutureUpdate;
}


Trigger:

trigger updateSomething on Account (after insert, after update) 
{
 
    /*  This trigger performs its logic when the call is not from @future */
    if(Utility.isFutureUpdate != true)
    {
 
        Set<Id> idsToProcess = new Se<Id>();
 
        for(Account acct : trigger.new)
        {
            if(acct.NumberOfEmployees > 500)
            {
                idsToProcess.add(acct.Id);
            }
        }
 
        /* Sending Ids to @future method for processing */
        futureMethods.processLargeAccounts(idsToProcess);
 
    }
}

Class:

public class FutureMethods
{
 
    @future
    public static void processLargeAccounts(Set<Id> acctIDs)
    {
 
        List<Account> acctsToUpdate = new List<Account>();
 
        /* isFutureUpdate is set to true to avoid recursion */
        Utility.isFutureUpdate = true;
        
        update acctsToUpdate;
    }
}

When to use triggers in Salesforce?

Triggers are used to perform immediate actions based on previous action.
Example: field update.
     A trigger is Apex code that executes before or after specific Data Manipulation Language (DML) events occur, such as before object records are inserted into the database, or after records have been deleted.
Syntax:
trigger triggerName on ObjectName (trigger_events)
{
    /*------------
    code_block
    -------------*/
}
where trigger_events can be a comma-separated list of one or more of the following events:
  1. before insert
  2. before update
  3. before delete
  4. after insert
  5. after update
  6. after delete
  7. after undelete

Trigger to create child object after checking some condition in parent record?

Sample Trigger:

trigger ageInterest on Member__c (after insert, after update)
{
    for(Member__c mem:trigger.New)
    {
        if(mem.Age__c == 18)
        {
            Interest__c it = new Interest__c(Name = 'Ghost Movies',Member__c = mem.ID);
            insert it;
        }
    }
}


Here Member__c is Parent object and Interest__c is child object.

Executing Trigger based on field value in Salesforce?

Sample Trigger:

 trigger test on Member__c (after insert)
{
    List<Case> cases = new List<Case>();

    for(Member__c mem:Trigger.new)
    {
        if(
mem.Comments__c != null || mem.Comments__c != '')
        {
                Case newCase = new Case(subject='Material',Status='New',Origin='Web');           
                insert newCase;

        }
    }

}

Welcome message and update notification trigger in Salesforce?

Sample Code:

trigger memberInviteNotify on Member__c (after insert,after update)
{
    for(Member__c member:trigger.New)
    {
        String[] toAddresses = new String[] {member.E_Mail_Id__c};
        String messageBody;
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        mail.setToAddresses(toAddresses);
       
        //Email invitation
        if(trigger.isInsert)
        {
            mail.setSubject('Welcome to Sweet 16 Siebel Batch');
            messageBody = '<html><body>Hi ' + member.Name + ',<br>Welcome to Sweet 16.<br><br><b>Regards,</b><br>Magulan D</body></html>';
            mail.setHtmlBody(messageBody);  
        }
       
        //Email notification
        if(trigger.isUpdate)
        {
            mail.setSubject('Updates in your details');
            messageBody = '<html><body>Hi ' + member.Name + ',<br>Changes have been made to your details. <br><br>Contact administrator if you are not responisble.</body></html>';
            mail.setHtmlBody(messageBody);
        }
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
    }
}

Trigger.old example in Salesforce?

Sample Trigger:

trigger userNamEmaiil on User (before insert, before update)
{
    if(trigger.isInsert)
    {
        for(User u : trigger.new)
        {
            if(u.name != u.Email)
            {
                u.addError('Username and Email should be same');
            }          
        }
    }
    else if(trigger.isUpdate)
    {   
        for(User o : trigger.old)
        {
            for(User n : trigger.new)
            {
                if(o.email != n.Email)
                {
                    n.addError('Email address cannot be changed');
                }  
            }
        }
    }
}


Output:

Triggers in Salesforce

Apex can be invoked through the use of triggers. A trigger is Apex code that executes before or after the following types of operations:

• insert
• update
• delete
• merge
• upsert
• undelete

For example, you can have a trigger run before an object's records are inserted into the database, after records have been deleted, or even after a record is restored from the Recycle Bin.

You can define triggers for any top-level standard object, such as a Contact or an Account, but not for standard child objects, such as a ContactRole.

• For case comments, click Your Name > Setup > Customize > Cases > Case Comments > Triggers.
• For email messages, click Your Name > Setup > Customize > Cases > Email Messages > Triggers.

Triggers can be divided into two types:

• Before triggers can be used to update or validate record values before they are saved to the database.
• After triggers can be used to access field values that are set by the database (such as a record's Id or lastUpdated field), and to affect changes in other records, such as logging into an audit table or firing asynchronous events with a queue.

Code coverage for Task Trigger?

Trigger:

trigger deletetask on Task (before delete)
    {
    if(System.Trigger.IsDelete)
        {
        for (Task t : trigger.old)
            if (t.check__c == 1)
                {
                t.addError('Error: You cannot delete a Task when it is marked complete.');
                }
        }         
}


Test Class:

@isTest
public class testClass
{
    static testmethod void test()
    {
        Task t = new Task(Type = 'Email',check__c = 0);
        insert t;
        delete t;
    }
}


Output: