Thursday 25 June 2015

Prevent Duplicate Records in Salesforce by Comparing more than one fields


Quick Summary on Logic:

      The below trigger written in Lead object using equals and hashCode Method. This methods are used on uniqueness.  Each hashCode value is unique. 

For example: test@mail.com and Test@mail.com will provide different hashCode values.

Object: Lead
Logic: If Lead record contains same Email and Company Name, then the below trigger will prevent duplication.


Apex Class

  1. public class DeDupeWrapper
  2. {
  3.     public String email;
  4.     public String company;
  5.    
  6.     public DeDupeWrapper(String email, String company)
  7.     {
  8.         this.email = email != null ? email.toLowerCase() : email;
  9.         this.company = company != null ? company.toLowerCase() : company;
  10.     }
  11.    
  12.     public Boolean equals(Object obj)
  13.     {
  14.         if (obj instanceof DeDupeWrapper)
  15.         {
  16.             DeDupeWrapper p = (DeDupeWrapper)obj;
  17.             return ((email == p.email) && (company == p.company));
  18.         }
  19.         return false;
  20.     }
  21.    
  22.     public Integer hashCode()
  23.     {
  24.         return (email.hashCode() * company.hashCode());
  25.     }
  26. }


Apex Trigger

  1. trigger DeDuplicateLead on Lead(before insert, before update)
  2. {
  3.     Map<DeDupeWrapper, Lead> leadMap = new Map<DeDupeWrapper, Lead>();
  4.     Map<String, String> duplicateMap = new Map<String, String>();
  5.    
  6.     for (Lead currLead: Trigger.new)
  7.     {
  8.       if((Trigger.isInsert && (currLead.Email != null && currLead.company != null))  ||
  9.            (Trigger.isUpdate && (currLead.Email != Trigger.oldMap.get(currLead.Id).Email ||
  10.                                  currLead.Company != Trigger.oldMap.get(currLead.Id).Company)))
  11.         {
  12.            
  13.             DeDupeWrapper key = new DeDupeWrapper(currLead.Email, currLead.Company);
  14.            
  15.             if (leadMap.containsKey(key))
  16.             {
  17.                 currLead.Email.addError('DUPLICATE CAUGHT...!');
  18.             }
  19.             else
  20.             {
  21.                 leadMap.put(key, currLead);
  22.             }
  23.         }
  24.     }
  25.    
  26.     for(DeDupeWrapper currWrap : leadMap.keySet())
  27.     {
  28.         duplicateMap.put(currWrap.Email, currWrap.company);
  29.     }
  30.    
  31.     for (Lead lead : [SELECT Email,Company FROM Lead WHERE Email in: duplicateMap.keySet() AND Company in: duplicateMap.values()])
  32.     {
  33.         DeDupeWrapper key = new DeDupeWrapper(lead.Email, lead.Company);
  34.         Lead newLead = leadMap.get(key);
  35.         if(newLead != null)
  36.         {
  37.             newLead.addError('DUPLICATE RECORD ALREADY FOUND');
  38.         }
  39.     }
  40. }

equlas and hashcode method example in Salesforce

Here is the simple real time example of Equlas and HashCode method usage in Salesforce,

You can compare more than one field in SOQL Query for bulk insert and update operation. Based on the comparison search result you can do your logic. The below example will explain the functionality as follows,

Case Object:

1. Status(Standard Field)
2. Description(Standard Field)

Account Object:

1. Name(Standard Field)
2. AccountNumber(Standard Field)

Scenario:

While insert/update Case record, if both status and Description field matches to the Account name and AccountNumber means, i need to update the case with matched account.

For e.g:
Case Status: Arun
Case Description: 123

Account Name: Arun
AccountNumber: 123

The above case record matched with account field values. So in this scenario need to update account field value on case. If Multiple/No related accounts found, then I just updated another field in Case.

Wrapper Class with Equals and HashCode Method:


  1. public class PairStrings {
  2.     String subject, description;
  3.     public PairStrings(String str1, String str2) {
  4.         subject = str1;
  5.         description = str2;
  6.     }
  7.     public Boolean equals(Object obj) {
  8.         if (obj instanceof PairStrings) {
  9.             PairStrings p = (PairStrings)obj;
  10.             return ((subject==p.subject) && (description==p.description));
  11.         }
  12.         return false;
  13.     }
  14.     public Integer hashCode() {
  15.         return (31 * subject.hashCode()) ^ description.hashCode();
  16.     }
  17. }


Trigger on Case Object:


  1. trigger CaseTrigger1 on Case (before insert, before update)
  2. {
  3.     Set<String> subjects = new Set<String>();
  4.     Set<String> descriptions = new Set<String>();
  5.     for(Case currCase : Trigger.New)
  6.     {
  7.         subjects.add(currCase.subject);
  8.         descriptions.add(currCase.Description);
  9.     }
  10.    
  11.     Map<PairStrings, List<Account>> accountMap = new Map<PairStrings, List<Account>>();
  12.     for(Account currAcc : [SELECT Id, Name, Description, AccountNumber FROM Account WHERE Name in:subjects AND AccountNumber in:descriptions])
  13.     {
  14.         PairStrings ps = new PairStrings(currAcc.Name, currAcc.AccountNumber);
  15.        
  16.         if(!accountMap.containsKey(ps))
  17.         {
  18.             accountMap.put(ps, new List<Account>{currAcc});
  19.         }
  20.         else
  21.         {
  22.             accountMap.get(ps).add(currAcc);
  23.         }
  24.     }
  25.    
  26.     for(Case currCase : Trigger.new)
  27.     {
  28.         PairStrings ps = new PairStrings(currCase.subject, currCase.Description);
  29.        
  30.         if(accountMap.containsKey(ps))
  31.         {
  32.             if(accountMap.get(ps).size() > 1)
  33.             {
  34.                 currCase.Account_Status__c = 'More than one account found';
  35.             }
  36.             else
  37.             {
  38.                 currCase.AccountId = accountMap.get(ps)[0].Id;
  39.             }
  40.         }
  41.         else
  42.         {
  43.             currCase.Account_Status__c = 'No matching account found';
  44.         }
  45.     }
  46.    
  47. }


Wednesday 24 June 2015

Salesforce Summer'15 Maintenance / Release Exam Notes

       Here is the quick summary of Salesforce.com Summer'15 quick glance of release notes. This will definitely helpful for your Summer'15 Maintenance exam.

Chatter


Edit Feed Posts and Comments:

It Ensure that your feed posts are accurate and up-to-date with feed post editing.

"Allow users to edit posts and comment" chatter setting option is enabled by default. To verify go to the below path in your salesforce organization,

Setup | Customize | Chatter | Settings 



The following Profile Level Permission available to handle the edit options on post,

1. Edit My Own Posts 
2. Edit Posts on Records I Own (It's disabled by default for existing profiles) --> Users who have Modify All Profile Permission in profile can edit all post and comments, regardless of this permission.

Chatter Free, Chatter External, and Customer Portal Users do not have the ability to edit their post and comments.


Share Any File With Library:

Users can share Chatter and external files with Library. Using this feature you can share the Files you own, Shared Files, and External files.

This feature is disabled by default, to enable this navigate like below,



File user interface allows sharing files with libraries.


Sync Content Files

All your files from content libraries, including private files, can be synced in Chatter. Using this feature, users allows to sync their files from library. 


"Enable files sync" option from the above navigation.


Salesforce Files to Folder

When you sync a file in Chatter, now you can sync it to a folder.


User must need to install app in their desktop as well salesforce file sync must be enabled.


Managing Custom object records added to the Groups:

It allows which custom object records end users can add to chatter group.

"Allow in Chatter Groups" option is available in object setting. If you create/edit object you will find the below option.



Force.com

Set up Assistance:

It's now available for newly activated organization. It provides helpful videos and guides in importing sales data and basic configuration. Set up Assistance option available in the side bar.

Data Loader:

Data Loader now available on Mac OS

Login Access Policy:

From Summer 15 onward, "Administrators Can Log in as Any User setting" allows login as any users without need of end user support.



Permission needed for this feature is,

1. The The Modify All permission enabled for administrator.
2. The View and Setup configuration permission enabled for delegated administrator. 


Mobile

Customize actions in the salesforce1 Action bar:

Developer can override the predefined actions and specify separate set of actions to appear in salesforce1 web interface.

1. Action category pallet renamed to quick action.
2. New category named as Salesforce1 Actions.
3. Actions in the publisher section is renamed to Quick Actions publisher section.


Lightning App Builder:

It's a point and click tool that make it easy to create custom page for salesforce1. It provides the following features,

1. Single page application.
2. Dashboard style application.
3. Applications to solve a particular task.


Services

Macro:

Support agents who use Case Feed can use macros to complete repetitive tasks—such as selecting an email template, sending an email to a customer, and updating the case status—all in a single click. Macros save time and add consistency to support agents’ work.

The following enhancement are available from summer 15,

1. Run Bulk macro on multiple records at the same time. 
2. Search and attach articles to cases.
3. Post to social networks.
4. Replace field value in Case.
5. Insert field values in case.


Add Report Charts in Console Side bar:

1. You can add Matrix or Summary Report.

2. Report folder must be shared who accessing the specified report.

For this, You need to add the report in page layout, and you cannot move the side bar report between sandbox and production. It's not avail on Meta data API.



Thanks for reading this post...!

Exam Questions:

Dev 401 Summer 15 Maintenance 

Admin 201 Summer 15 Maintenance 

Activities: Assign Tasks to a Queue Salesforce Lightning

Salesforce announced to assign Tasks to a Queue beginning from Spring'20 release. How does it work? In Setup, enter Queues in th...