0

I'm working with the DocuSign managed package and looking to allow invocable variable input from process builder. Below is the class I have created and it compiles fine but when I go to execute the apex from process builder I get the following error:

Can’t Save Record We can't save this record because the “Workflow Step Process” process failed. Give your Salesforce admin these details. An Apex error occurred: System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out Error ID: 1251372889-86454 (-1174802342)ork pending. Please commit or rollback before calling out Error ID: 1251372889-86454 (-1174802342)

public class SendWithDS {
     @InvocableMethod
    
    public static void sendEnvelopeMethod(List <InvocableVariables> request){
        
        Id mySourceId = request[0].mySourceId;
        Id myContactId = request[0].myContactId;
        
        //Salesforce contact record as recipient 
        Contact myContact = [SELECT Id, Name, Email FROM Contact where id =: myContactId];
        
        //use the Recipient.fromSource method to create the Recipient
        dfsle.Recipient myRecipient = dfsle.Recipient.fromSource(
            myContact.Name, // Recipient name
            myContact.Email, // Recipient email
            null, //Optional phone number
            'Signer 1', //Role Name. Specify the exact role name from template
            new dfsle.Entity(myContact.Id)); //source object for the Recipient
        // Create an empty envelope.
        dfsle.Envelope myEnvelope = dfsle.EnvelopeService.getEmptyEnvelope(
            new dfsle.Entity(mySourceId));
        
        //add Recipient to the Envelope
        myEnvelope = myEnvelope.withRecipients(new List<dfsle.Recipient> { myRecipient });
        
        //myTemplateId contains the DocuSign Id of the DocuSign Template
        dfsle.UUID myTemplateId = dfsle.UUID.parse('0afb9e85-aa02-4fc8-8ad6-ec354c27d7a9');
        
        //create a new document for the Envelope
        dfsle.Document myDocument = dfsle.Document.fromTemplate(
            myTemplateId, // templateId in dfsle.UUID format
            'myTemplate'); // name of the template
        
        //add document to the Envelope
        myEnvelope = myEnvelope.withDocuments(new List<dfsle.Document> { myDocument });
        
        // Send the envelope.
        myEnvelope = dfsle.EnvelopeService.sendEnvelope(
            myEnvelope, // The envelope to send
            true); // Send now?
        
        // Retrieve the five most recent envelope statuses from the Salesforce source object.
        // The status results are sorted oldest to newest.
        List<dfsle.Envelope.Status> myStatus = dfsle.StatusService.getStatus(
            new Set<Id> { // IDs of the Salesforce objects with associated status.
                mySourceId
                    },
            5); // Maximum number of records to return.
        
        
    }
    
    public class InvocableVariables{
        // The ID of the initiating Salesforce object and recipient
        @InvocableVariable public Id mySourceId;
        @InvocableVariable public Id myContactId;
    }
}

I have looked into the documentation for the error but I'm very new to apex and development in general and I just can't seem to figure out here I'm going wrong. Any help is appreciated. Thank you

3 Answers 3

1

You can't make a callout after making a DML transaction. This restriction prevents unnecessarily long locks in the database, which can cause contention between users. The usual fix for this is to move your request to a @future method (although also possible to use Queueable for your situation). Note that this also means it's not possible to return a value that can be immediately used in the flow you've built, as the callout will be delayed until the flow completes. As a side note, your code isn't bulkified, so be aware that bulk updates that trigger this flow won't work as you expect.

The easiest fix from your current position is to modify the code so it can be called asynchronously:

public class SendWithDS implements Queueable {
    InvocableVariables[] request;
    public SendWithDS(InvocableVariables[] request) {
        this.request = request;
    }
    @InvocableMethod    
    public static void sendEnvelopeMethod(List <InvocableVariables> request){
        System.enqueueJob(new SendWithDS(request));
    }
    public void execute(QueueableContext context) {
        Id mySourceId = request[0].mySourceId;
        // ... rest of code from original sendEnvelopeMethod here
    }        
    // Don't forget InvocableVariables class here
}
1
  • Thank you so much this worked perfectly for me!
    – Jas
    Commented May 19, 2021 at 13:50
0

This error is related to the fact that you're performing a callout after performing a DML statement (check this article).

In order for it to work, you can either have to split the DML/callout into different transactions or make sure the HTTP callout is performed before the DML statements.

Best regards!

0

Your record will not get committed in invokable method and above script is hitting an endpoint (HTTP Callout). You should create a future method (a method with @future annotation) and put invokable method script in this future method. After that call this future method in your invokable method.

1
  • Please do not ask for answer acceptance or upvotes on Salesforce Stack Exchange. The community will provide that feedback where appropriate. Thanks!
    – David Reed
    Commented May 18, 2021 at 14:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .