function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
golugolu 

callout from the trigger using queuable

In the below code , i am doing a callout in line 23 and 24. But in debug logs it throws error saying "i cannot do a callout from a trigger". I tried using future . But in future i cannot pass list of SObject. I am not able to pass the code in queueable context. Can anyone please help to make it work. 
public class CommunicatoHistoryHelper implements Queueable, Database.allowscallouts{
    public static void createUpdateActivity(List<Communicato_History__c> lstComHistory){
        SMS_Configuration__c smsConfig = SMS_Configuration__c.getOrgDefaults();
        List<id> activityids = new List<Id>();
        List<Task> updateLstTask = new List<Task>();
        List<Communicat_O_activity__c> updateComActivity = new List<Communicat_O_activity__c>();
        for (Communicato_History__c com : lstComHistory) {
            String s = com.communicat_o__Activity_Ids__c;
            if(s.contains('(') || s.contains(')')) {
                s=s.replace('(','').replace(')','');
            }
            system.debug('s' + s);
            if (com.Status__c == CommunicatoUtilityClass.ACTIVITY_STATUS_COMPLETED){ 
                activityids.add(s);
                system.debug('activityids14' + activityids);
            }
        }
        List<API_Configuration__mdt> apiConfig;
        apiConfig = [SELECT Class_Name__c FROM API_Configuration__mdt LIMIT 1];
        try{
            if(activityids.size() > 0 && activityids.size() == 1){
                Type t = Type.forName(apiConfig[0].class_name__c);
                MessageService message = (MessageService)t.newInstance();
                message.sendSingleMessage('xxxxxxxxxx','testsms');
            }
        }
        catch(Exception e){
            system.debug('Class name is not set in api configuration metadata record');  
        }
        try{
            if(activityids.size() > 1){
                Type t = Type.forName(apiConfig[0].class_name__c);
                MessageService message = (MessageService)t.newInstance();
                message.sendBulkMessage();    
            }
        }
        catch(Exception e){
            system.debug('Class name is not set in api configuration metadata record');
        }
        
        List<SObject> sObj = new List<SObject>();
        String strQuery;
        List<Task> lstTask = new List<Task>();
        List<Communicat_O_activity__c> comActivity = new List<Communicat_O_activity__c>();
        if(smsConfig.Use_Salesforce_Activity__c){
            strQuery = 'Select Status FROM Task WHERE Id IN ';strQuery += ':activityids';
        }
        else{
            strQuery = 'Select Status__c FROM Communicat_O_activity__c WHERE Id IN ';strQuery += ':activityids';
            
        }
        sObj = Database.query(strQuery);
        for(sObject s : sObj){
            if(smsConfig.Use_Salesforce_Activity__c){
                Task t = (Task)s;
                t.status = CommunicatoUtilityClass.ACTIVITY_STATUS_COMPLETED;
                lstTask.add(t);
            }   
            
            else{
                Communicat_O_activity__c com = (Communicat_O_activity__c)s;
                com.status__c = CommunicatoUtilityClass.ACTIVITY_STATUS_COMPLETED;
                comActivity.add(com);
            }
        }
        if(lstTask.size()>0){
            update lstTask;
        }
        if(comActivity.size()>0){
            update comActivity;
        }
    }
    public void execute(QueueableContext context) {
       // this.createUpdateActivity();
    }
}

 
Ramesh DRamesh D
@golu
You can't pass sObjects to @future methods:
Methods with the future annotation must be static methods, and can only return a void type. The specified parameters must be primitive data types, arrays of primitive data types, or collections of primitive data types. Methods with the future annotation cannot take sObjects or objects as arguments.
The reason why sObjects can’t be passed as arguments to future methods is because the sObject might change between the time you call the method and the time it executes. In this case, the future method will get the old sObject values and might overwrite them. To work with sObjects that already exist in the database, pass the sObject ID instead (or collection of IDs) and use the ID to perform a query for the most up-to-date record. The following example shows how to do so with a list of IDs.


There is the workaround using JSON serialization/deserialization so that you can pass the serialized string of your objects to the future method. This is especially usefull when your objects are not available in the database to query them back.
public AddressFuture () {

List<String> addresses = new List<String>();
AddressHelper ah1 = new AddressHelper('1 here st', 'San Francisco', 'CA', '94105');
AddressHelper ah2 = new AddressHelper('2 here st', 'San Francisco', 'CA', '94105');
AddressHelper ah3 = new AddressHelper('3 here st', 'San Francisco', 'CA', '94105');

//serialize my objects
addresses.add(JSON.serialize(ah3));
addresses.add(JSON.serialize(ah2));
addresses.add(JSON.serialize(ah3));

doFutureCall(addresses);

}
 
@future
  static void doFutureCall(List<String> addressesSer) {

  	AddressHelper currAddress = null;

     for (String ser : addressesSer)
     {

     	 currAddress = (AddressHelper) JSON.deserialize(ser, AddressHelper.class);
     	 System.debug('Deserialized in future:'+currAddress.street);
     }
  }

public with sharing class AddressHelper {

    public String street {set; get;}
    public String city {set; get;}
    public String state {set; get;}
    public String zip {set; get;}

    public AddressHelper(String s, String c, String st, String z) {
        street = s;
        city = c;
        state = st;
        zip = z;
    }
}

I hope you find the above solution helpful. If it does mark as best answer to help others too.
Thanks,
Ramesh D
golugolu
Cannot I do it with queueable somehow Instead of future ?
Ramesh DRamesh D
@golu 
You can try something like below
//Call your queue job
 Map<string,string> Updatelist=new Map<string,string>();
        Updatelist.put('2345234','2345234');
        System.Queueable job = new FetchQueue (JSON.serialize(Updatelist));
        System.enqueueJob(job);

//Your queue Job
public class FetchQueue implements System.Queueable{
    
    private  string jString;
    
    public FetchQueue (string jsonString) {
        this.jString = jsonString;
    }
    
    public void execute(System.QueueableContext objContext)
    {
       yourclass.Getmydata(jString);
    }
}

//Inside your getmydata
    public static void getmydata(string jsonMap)
    {
 Map<string,string> originalMap = ( Map<string,string>)JSON.deserialize(jsonMap,  Map<string,string>.class);
//play with originalMap 

}

I hope you find the above solution helpful. If it does mark as best answer to help others too.
Thanks,
Ramesh D