[SalesForce] How to create Account,Contact records based on the web-case data if contact email not existed in system

I have some fields in case object which are filling from web-to-case form.
when we submit the case form, if email is found in contacts associated contact and account will be auto populated.
My requirement is :

  1. I have to create new Account and its child contact if email is not in contacts
  2. I have to fill accountId,contactId fields with above data in case record.

For this I tried in two ways,
1. I have written a before insert trigger on Case and tried to create account and it's child contact. Both account and contact are created, but accountId,ContactId are not filled in case.
2. I have written a schedule class which is scheduled after one minute of current time from after insert trigger. In that class I implemented the above logic and tried to update the case record. But I got Record is read-only error.

Please help me to achieve this.
Trigger:

trigger CaseTrigger on Case (after insert) 
{
    if(Trigger.isAfter && Trigger.isInsert)
    {

        CaseAutoFill ca = new CaseAutoFill(Trigger.New);
        DateTime nextRun = system.now().addMinutes(1);
        String cron = nextRun.second()+' '+nextRun.minute()+' '+nextRun.hour()+' ? '+nextRun.month()+' * '+nextRun.year();
        String jobID = system.schedule('ca-'+system.now(), cron, ca); 
    }
}

Schedule class:

global class CaseAutoFill implements Schedulable 
{
    list<Case> newCases;
    global CaseAutoFill(list<Case> newCases)
    {
        this.newCases = newCases;
    }
    global void execute(SchedulableContext SC) 
    {
        system.debug('newCases..!'+newCases);
        Set<String> accEmails = new Set<String>();
        Set<String> contactEmails = new Set<String>();
        for(Case c : newCases)
        {
            accEmails.add(c.PR_Email__c);
            contactEmails.add(c.ContactEmail);
        }
        system.debug('accEmails..!'+accEmails);
        system.debug('contactEmails..!'+contactEmails);

        //Account map
        list<Account> accounts = [select Id,PO_Email__c from Account where PO_Email__c IN: accEmails];
        map<String,Account> accountMap = new map<String,Account>();
        for(Account acc : accounts){
            accountMap.put(acc.PO_Email__c,acc);
        }

        //Contact map
        list<Contact> contacts = [select Id,Email from Contact where Email IN: contactEmails];
        map<String,Contact> contactMap = new map<String,Contact>();
        for(Contact con : contacts){
            contactMap.put(con.Email,con);
        }

        //looping accounts
        list<Account> newAccounts = new list<Account>();        
        for(Case c : newCases)
        {
            Account acc = new Account();
            acc.Name = c.Name_of_Organization__c;
            acc.PO_Email__c = c.PR_Email__c;
            newAccounts.add(acc);
        }
        insert newAccounts;
        for(Account acc : newAccounts){
            accountMap.put(acc.PO_Email__c,acc);
        }

        //looping contacts
        list<Contact> newContacts = new list<Contact>();        
        for(Case c : newCases)
        {
            if(!contactMap.containsKey(c.ContactEmail))
            {
                Contact con = new Contact();
                if(accountMap.containsKey(c.PR_Email__c)){
                    con.accountId = accountMap.get(c.PR_Email__c).Id;
                }                
                con.Email = c.ContactEmail;
                con.lastName = c.User_First_and_Last_Name__c;
                con.firstName = c.User_First_and_Last_Name__c;
                con.MobilePhone = '1234568790';
                con.Phone = '1234568790';
                newContacts.add(con);
            }
        }
        insert newContacts;
        for(Contact con : newContacts){
            contactMap.put(con.Email,con);
        }
        system.debug('accountMap..!'+accountMap);
        system.debug('contactMap..!'+contactMap);

        //final verification
        for(Case c : newCases)
        {
            if(String.isBlank(c.AccountId) && accountMap.containsKey(c.PR_Email__c))
            {
                c.AccountId = accountMap.get(c.PR_Email__c).Id;
            }
            if(String.isBlank(c.contactId) && contactMap.containsKey(c.ContactEmail))
            {
                c.contactId = contactMap.get(c.ContactEmail).Id;
            }
        }   
        system.debug('newCases..!'+newCases);
        update newCases;     
    }
}

Best Answer

Record is read-only in after trigger context.

So, you need to fetch case records again and update those cases.

Here is the approach:

trigger CaseTrigger on Case (after insert) 
{
    Set<Id> caseIds = new Set<Id>();
    if(Trigger.isAfter && Trigger.isInsert)
    {
        for(Case caseObj: Trigger.new)
        {
            if(/* put necessary conditions */)
            {
                caseIds.add(caseObj.Id);
            }
        }

        List<Case> lstCase = [SELECT Id, AccountId, ContactId, ..... FROM Case WHERE Id IN:caseIds];

        CaseAutoFill ca = new CaseAutoFill(lstCase);
        DateTime nextRun = system.now().addMinutes(1);
        String cron = nextRun.second()+' '+nextRun.minute()+' '+nextRun.hour()+' ? '+nextRun.month()+' * '+nextRun.year();
        String jobID = system.schedule('ca-'+system.now(), cron, ca); 
    }
}

or

this way, without SOQL query

trigger CaseTrigger on Case (after insert) 
{
    List<Case> lstCase = new List<Case>();
    if(Trigger.isAfter && Trigger.isInsert)
    {
        for(Case caseObj: Trigger.new)
        {
            if(/* put necessary conditions */)
            {
                Case newCase = new Case (Id=caseObj.Id);
                lstCase.add(newCase);
            }
        }

        CaseAutoFill ca = new CaseAutoFill(lstCase);
        DateTime nextRun = system.now().addMinutes(1);
        String cron = nextRun.second()+' '+nextRun.minute()+' '+nextRun.hour()+' ? '+nextRun.month()+' * '+nextRun.year();
        String jobID = system.schedule('ca-'+system.now(), cron, ca); 
    }
}
Related Topic