Showing posts with label APEX trigger. Show all posts
Showing posts with label APEX trigger. Show all posts

Thursday, 1 April 2021

Automatically create new contact from Email-To-Case

Requirement : 
While working on one of the requirement of Commerce sector project for a client based out GA, USA; there was a requirement to build support system which can automatically create new case and task for Contact. For new Contact,  it should create the new contact first in Salesforce and then create new case and task under it. 


Challenge : 
Salesforce automatically creates Case from Email. It is called Email-to-Case. This feature also creates tasks along with the Case. Hence the first half of the requirement is solved using the Salesforce standard feature provided by Salesforce Service Cloud. The main challenge for us was to create a new contact whenever we receive an email from a new email address because Salesforce doesn't provide this feature in Email-to-Case. Although, we can install the Email-to-Case Premium package as additional subscription which requires license.

Solution : 
Instead of subscription, We have used the Salesforce Service Cloud provided Email-to-Case feature to create a new case from an e-mail and Apex trigger to create new contact if email address is not exist. 

We can use Email-to-Case in 2 different ways : 
  1. Email-to-Case 
  2. On-demand Email-to-Case
The main difference between these two is Email-to-Case accepts the emails larger than 25 MB while On-Demand Email-to-Case accepts the emails less than 25 MB.

Note : Once you enable Email-to-Case, you cannot disable it. However, you can disable the On-Demand Service.

To setup Email-to-Case service follow the link Email-to-Case. Once setup is completed you will have configuration as shown below.


Now, you also need to configure routing address for the account which is being used as Customer Support in your organization.






Now, you will be having a Salesforce generated dynamic email address that can be used to create the Case.

Since the generated email address is too long to remember, you can configure an email routing address at your support account, so that the email received to your customer support Account, will be forwarded to the Salesforce.

Please refer the Email routing to configure forwarding the email to Salesforce generated dynamic email address. 


For second part of the requirement, to create new contact for the unknown/new email address received by salesforce, we have created a Apex trigger on Case Object. Refer below code for that.  

The trigger has the mechanism to check whether received email address is exist in contacts objects or not.  

If the contact exists with that email address, the case will be assigned to that contact.  

If the contact doesn’t exist, a new contact will be created and then the case will be assigned to that contact. 

Trigger to create contact : 

trigger TriggertoCreateContactforCase on Case (before insert) {
    if(Trigger.isBefore){
        if(Trigger.isInsert){
            List<String> insertedEmailAddresses = new List<String>();
            // Create a list of email addresses for newly inserted case where contact is not set
            for (Case cs:Trigger.new) {
                if (cs.ContactId==null && cs.SuppliedEmail!='' || cs.SuppliedEmail!=null) {
                    insertedEmailAddresses.add(cs.SuppliedEmail);
                }
            }          
            
            Set<String> exstingEmailSet = new Set<String>();
            if(insertedEmailAddresses.size() > 0){
                // Create a set of Email address which are already available in contact
                for (Contact c:[Select Id,Email From Contact Where Email in:insertedEmailAddresses]) {
                    exstingEmailSet.add(c.Email);
                }
            }
            
            Contact contTemp = new Contact();
            List<String> Emailheader = new List<String>();
            List<Case> casesToUpdateList = new List<Case>();
            Map<String,Contact> emailToContactMap = new Map<String,Contact>();
            
            // For all the cases with a null contactId, We will create a contact
            for (Case c:Trigger.new) {
                if (c.ContactId==null && c.SuppliedName!=null && c.SuppliedEmail!=null && c.SuppliedName!='' &&
                    !c.SuppliedName.contains('@') && c.SuppliedEmail!='' && !exstingEmailSet.contains(c.SuppliedEmail)) {
                        Emailheader = c.SuppliedName.split(' ',2);
                        if (Emailheader.size() == 2) {
                            contTemp.FirstName=Emailheader[0];
                            contTemp.LastName=Emailheader[1];
                            contTemp.Email=c.SuppliedEmail;
                            emailToContactMap.put(c.SuppliedEmail,contTemp);
                            casesToUpdateList.add(c);
                        }
                    }
            }
            
            // Inserting Contact
            List<Contact> contactList = new List<Contact>();
            if(emailToContactMap.keyset().size() > 0){
                contactList = emailToContactMap.values();
                insert contactList;
            }
            
            // Updating Cases
            if(contactList.size()>0) {
                for (Case cs:casesToUpdateList) {
                    contTemp = emailToContactMap.get(cs.SuppliedEmail);
                    cs.ContactId = contTemp.Id;
                }
            }
        }
    }
}

Summary : 

By following the above steps, we have achieved the requirement. Now, whenever an email is received to the routing email address, it will automatically create a case and task for that case. While creating the case if the contact is not exist for that email address, the trigger will create a contact and then create a case for that contact. 

If you have any questions you can reach out our Salesforce Consulting team here.

Tuesday, 15 September 2020

[SOLVED]: Issue on getting Parent record-Id (whoid) while retrieving Task details generated through Email-To-Task

Requirement:
There was a requirement to track Sales person interaction with Customer which was being done via various Email Platforms such as Outlook, Gmail, Yahoo. We have used Email-To-Task to create task for such interactions. We need to track last interaction with customer by Sales\Support Person and get Due Date of Completed Task and auto populate it in "Last Sales Activity Date" (custom field) of related Contact/Lead record.

Challenge: 
The major challenge – When the Email is received to Salesforce, the task is generated and automatically linked to the relevant Contact/Lead record using Salesforce Email Configuration OOTB feature. For such Tasks, if Apex trigger is fired on the task object and at that time, we were unable to obtain the parent Id of Task generated via Email.

Solution:
To overcome this limitation, we developed a custom solution that involves creating an apex class named EmailTask having future method. Using the future method we can get parent recordId(Contact/Lead record), as it runs after some minor delay. The class contains the mechanism for retrieving Tasks List through Set of IDs that we need to pass as parameter from the Insert/Update Trigger. And after that, we need to get the Due Date (Activity Date) value from the Task and update to Last Sales Activity Date to the relevant parent record.

EmailTask Class


global class EmailTask {
    @future
    public static void getUpdate(set<Id> taskIds){
        //store WhoId and Task Record to the Map 
        Map<Id,Task> taskWhoMap = new map<Id,Task>();
        List<Task> TaskList = [Select Id,whoId,ActivityDate from task where Id IN :taskIds AND WhoId!= null];
        if(TaskList.size()>0){
            for(Task t : TaskList){
                taskWhoMap.put(t.WhoId,t); 
            }
        }
        
        if(taskwhomap.keySet().size()>0){
            List<Contact> contactList =[select Id, Last_Sales_Activity_Date__c from Contact where 
                                        Id =: taskwhomap.keySet()];
            
            if(contactList.size()>0){
                for(Contact c : contactList)
                {
                    if(taskwhomap.containsKey(c.Id)){
                        // store due date of task in Contact date field
                        c.Last_Sales_Activity_Date__c= taskwhomap.get(c.Id).ActivityDate;
                    }
                }
                // updating contact
                update contactList; 
            }
        }
        
        List<Lead> leadList =[select Id, Last_Sales_Activity_Date__c from Lead where 
Id =: taskwhomap.keySet()]; if(leadList.size()>0){ for(Lead l : leadList) { if(taskwhomap.containsKey(l.Id)){ // store due date of task in Lead date field l.Last_Sales_Activity_Date__c= taskwhomap.get(l.Id).ActivityDate; } } // updating Lead update leadList; } } }

Now, on the Task object, we need to configure an Apex Trigger which will initialize the EmailTask apex class on task creation/update.  

Email Trigger

trigger Email on Task (After insert,After update) {   
    if(trigger.Isafter){
        if(trigger.Isinsert || trigger.Isupdate){
            set<Id> TaskId = new set<Id>(); 
            for(Task t : trigger.new){
                TaskId.add(t.Id);
            }
            EmailTask.getUpdate(taskIds);
        }
    } 
}

Conclusion:

Using the above solution, we can achieve the requirement to generate the task for the relevant parent record, whenever the sales/support person communicates with the customer via E-mail and stores the interaction between them through generating Tasks and update the Last Sales Activity Date (custom field) to the relevant parent record. 

If you have any questions you can reach out our Salesforce Consulting team here.

Wednesday, 19 June 2019

Generate a PDF file with APEX Trigger in Salesforce

Requirement:
There was a requirement to generate a PDF file while inserting a new record in Account object and add it as an attachment (On-the-fly).

Challenge:
The main challenge was - when the record is saved, the apex trigger is fired on the account object, but at that time, we are unable to use the PageReference Class methods (generate PDF) within the trigger context, making it difficult to generate PDF with this OOTB Class/Method. 

Solution:
To generate PDF, we can use out-of-the-box PageReference Class method and it works only if there is not APEX trigger associated with the object. But if Apex trigger is associated with object while inserting a new record, it won't work.

To overcome this limitation, we developed a custom solution which involved creating an apex class called PDFGenerator. This class contains the mechanism to accept the HTML content and renders the PDF accordingly to the HTML specified. It will also attach the PDF file to the record as an Attachment.

PDFGenerator Class :


public with sharing class PDFGenerator
{
    public static final String FORM_HTML_START = '<HTML><BODY>';
    public static final String FORM_HTML_END = '</BODY></HTML>';

    public static void PDFGenerator(Account account)
    {
        String pdfContent = '' + FORM_HTML_START;

        try
        {
            pdfContent = '' + FORM_HTML_START;
            pdfContent = pdfContent + '<H2>Account Information in PDF</H2>';
            
            //Dynamically grab all the fields to store in the PDF
            Map<String, Schema.SObjectType> sobjectSchemaMap = Schema.getGlobalDescribe();
            Schema.DescribeSObjectResult objDescribe = sobjectSchemaMap.get('Account').getDescribe();
            Map<String, Schema.SObjectField> fieldMap = objDescribe.fields.getMap();
            
            //Append each Field to the PDF
            for(Schema.SObjectField fieldDef : fieldMap.values()) 
            {
                Schema.Describefieldresult fieldDescResult = fieldDef.getDescribe();
                String name = fieldDescResult.getName();
                pdfContent = pdfContent + '<P>' + name + ': ' + account.get(name) + '</P>';
            }

            pdfContent = pdfContent + FORM_HTML_END;

        }catch(Exception e)

        {
            pdfContent = '' + FORM_HTML_START;
            pdfContent = pdfContent + '<P>THERE WAS AN ERROR GENERATING PDF: ' + e.getMessage() + '</P>';
            pdfContent = pdfContent + FORM_HTML_END;
        }
        attachPDF(account,pdfContent);
    }  

    public static void attachPDF(Account account, String pdfContent)
    {
        try
        {
            Attachment attachmentPDF = new Attachment();
            attachmentPDF.parentId = account.Id;
            attachmentPDF.Name = account.Name + '.pdf';
            attachmentPDF.body = Blob.toPDF(pdfContent); //This creates the PDF content
            insert attachmentPDF;

        }catch(Exception e)
        {     
           account.addError(e.getMessage());
        }
    }
}

Now, we would modify an Apex Trigger, on Account object which will initialize the above created PDFGenerator apex class on the record creation (after insertion).

Account Trigger:


trigger AccountTrigger on Account (after insert)
{
    if(trigger.isAfter && trigger.isInsert)
    {  
        for(Account ac : trigger.new)
          {
             PDFGeneratorcController.PDFGenerator(ac);
          }          
    }  
}

This approach would generate a PDF within the context of the trigger, and help you overcome the challenge.

If you have any questions you can reach out our Salesforce Consulting team here.