I have a class where in I am trying to call a HTTP request. I have created a Mock Test and a Test class.
My Test class is successful with 28% code coverage but it fails in recognizing the call out methods I have used in my class Below is code
My Class -
public class PD_WelcomeMaroPost {
#future(callout=true)
public static void sendEmailThroughMaro(string myInpEmail) {
string successContacts = '';
string failureContacts = '';
List<Stripe_Subscripton__c> subsToUpdate = new List<Stripe_Subscripton__c>();
//List<Case> newCase = new List<Case>();
// SQL to fetch FBO who Joined Today
list<Account> conts = new list<Account> ([SELECT Id, name, Email_FLP_com__c,
(SELECT Id FROM Stripe_Subscriptons__r WHERE Start_Date__c= TODAY
AND Status__c='active'
AND Welcome_Email__C = false LIMIT 1)from account
where ID IN (select Distributor__c from Stripe_Subscripton__c
where Start_Date__c= TODAY AND Status__c='active'
AND Welcome_Email__C = false)
AND Email_FLP_com__c != NULL LIMIT 100]);
system.debug('>>>>>>>>>>' + conts);
overallEmail myEmail = new overallEmail();
for(Account c : conts){
string resultBodyGet = '';
myEmail.email.campaign_id = 172;
myEmail.email.contact.Email = c.Email_FLP_com__c;
myEmail.email.contact.first_name = c.name;
/**MAp<String, String> tags = new Map<String, String>();
tags.put('firstName', c.name);
myEmail.email.tags = tags;**/
system.debug('#### Input JSON: ' + JSON.serialize(myEmail));
try{
String endpoint = 'http://api.maropost.com/accounts/1173/emails/deliver.json?auth_token=j-V4sx8ueUT7eKM8us_Cz5JqXBzoRrNS3p1lEZyPUPGcwWNoVNZpKQ';
HttpRequest req = new HttpRequest();
req.setEndpoint(endpoint);
req.setMethod('POST');
req.setHeader('Content-type', 'application/json');
req.setbody(JSON.serialize(myEmail));
Http http = new Http();
system.debug('Sending email');
HTTPResponse response = http.send(req);
system.debug('sent email');
resultBodyGet = response.getBody();
system.debug('Output response:' + resultBodyGet);
maroResponse myMaroResponse = new maroResponse();
myMaroResponse = (maroResponse) JSON.deserialize(resultBodyGet, maroResponse.class);
system.debug('#### myMaroResponse: ' + myMaroResponse);
if(myMaroResponse.message == 'Email was sent successfully')
successContacts = successContacts + ';' + c.Email_FLP_com__c;
else
failureContacts = failureContacts + ';' + c.Email_FLP_com__c;
}
catch (exception e) {
failureContacts = failureContacts + ';' + c.Email_FLP_com__c;
system.debug('#### Exception caught: ' + e.getMessage());
}
c.Stripe_Subscriptons__r[0].Welcome_Email__c = true;
c.Stripe_Subscriptons__r[0].Welcome_Email_Sent_Date__c = system.today();
subsToUpdate.add(c.Stripe_Subscriptons__r[0]);
}
Update subsToUpdate;
}
public class maroResponse {
public string message {get;set;}
}
public class overallEmail {
public emailJson email = new emailJson();
}
public class emailJson {
public Integer campaign_id;
public contactJson contact = new contactJson();
//Public Map<String, String> tags;
}
public class contactJson {
public string email;
public string first_name;
}
}
My MockTest Class- I have used this Mockclass to generate Mock response. The documentation does not have a test method thus used the same format
#isTest
Global class PD_WelcomeMaroPostMock implements HttpCalloutMock {
Global HttpResponse respond(HttpRequest req) {
// Create a fake response
//
//System.assertEquals(JSON.serialize(myEmail),req.getbody());
HttpResponse res = new HttpResponse();
res.setHeader('Content-Type', 'application/json');
res.setBody('{"status":"success"}');
res.setStatusCode(200);
return res;
}
}
This is my Test class - This is the class I have used for the response. I have a successful insert job but my HTTP responses are failing.
#IsTest
private class PD_WelcomeMaroPost_test {
public class overallEmail {
public emailJson email = new emailJson();
}
public class emailJson {
public Integer campaign_id;
public contactJson contact = new contactJson();
}
public class contactJson {
public string email;
public string first_name;
}
#IsTest
private static void testemail() {
overallEmail myEmail = new overallEmail();
Account a = new Account();
a.Name ='Test' ;
a.Email_FLP_com__c = 'test#nextsphere.com';
insert a ;
Stripe_Subscripton__c s = new Stripe_Subscripton__c();
// insert subscription --
s.Distributor__c = a.Id;
S.Welcome_Email__c = TRUE;
S.Welcome_Email_Sent_Date__c = system.today();
s.Subscription_Id__c = 'sub_9H0LLYFZkekdMA' ;
INSERT S;
Test.setMock(HttpCalloutMock.class, new PD_WelcomeMaroPostMock());
String endpoint = 'http://api.maropost.com/accounts/1173/emails/deliver.json?auth_token=j-V4sx8ueUT7eKM8us_Cz5JqXBzoRrNS3p1lEZyPUPGcwWNoVNZpKQ';
HttpRequest req = new HttpRequest();
req.setEndpoint(endpoint);
req.setMethod('POST');
req.setHeader('Content-type', 'application/json');
req.setbody(JSON.serialize(myEmail));
Test.startTest();
PD_WelcomeMaroPost.sendEmailThroughMaro('test#nextsphere.com');
Test.stopTest();
}
}
When declaring a Mock myself, I declare it inside the test start transaction:
Test.startTest();
Test.setMock(WebServiceMock.class, new WebServiceMockImpl());
// Rest of test code here
Test.stopTest();
Also inside your test class you seem to only build the HTTP request and not send it try adding the below:
HttpResponse res = http.send(req);
if (res.getStatusCode() == 200) { } else { }
Related
I'm not a developer and we don't have one currently on our staff. So I looked all over the web and modified this Apex Class to suit my needs so that when an opportunity is marked as closed/won I get a small message in Slack.
It works great and I'd like to send this to Production. However, I didn't realize that I need to include a test for this and I am stuck on what that means.
Here's my Apex Class:
public with sharing class SlackPublisher {
private static final String SLACK_URL = 'https://hooks.slack.com/services/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';
public class Oppty {
#InvocableVariable(label='Opportunity Name')
public String opptyName;
#InvocableVariable(label='Opportunity Owner')
public String opptyOwnerName;
#InvocableVariable(label='Account Name')
public String acctName;
#InvocableVariable(label='Amount')
public String amount;
}
public class UrlMethods {
String BaseUrl; // The Url w/o the page (ex: 'https://na9.salesforce.com/')
String PageUrl; // The Url of the page (ex: '/apex/SomePageName')
String FullUrl; // The full Url of the current page w/query string parameters
// (ex: 'https://na9.salesforce.com/apex/SomePageName?x=1&y=2&z=3')
String Environment; // Writing code that can detect if it is executing in production or a sandbox
// can be extremely useful especially if working with sensitive data.
public UrlMethods() { // Constructor
BaseUrl = URL.getSalesforceBaseUrl().toExternalForm(); // (Example: 'https://na9.salesforce.com/')
}
}
#InvocableMethod(label='Post to Slack')
public static void postToSlack ( List<Oppty> opps ) {
Oppty o = opps[0]; // bulkify the code later
Map<String,Object> msg = new Map<String,Object>();
msg.put('text','Deal ' + o.opptyName + ' was just Closed/Won' + ':champagne:' + '\n' + 'for a total of ' + '$' + o.amount);
msg.put('mrkdwn', true);
String body = JSON.serialize(msg);
System.enqueueJob(new QueueableSlackPost(SLACK_URL, 'POST', body));
}
public class QueueableSlackPost implements System.Queueable, Database.AllowsCallouts {
private final String url;
private final String method;
private final String body;
public QueueableSlackPost(String url, String method, String body) {
this.url = url;
this.method = method;
this.body = body;
}
public void execute(System.QueueableContext ctx) {
HttpRequest req = new HttpRequest();
req.setEndpoint(url);
req.setMethod(method);
req.setBody(body);
Http http = new Http();
HttpResponse res = http.send(req);
}
}
}
and what I found online as a base for a test was this:
#isTest
private class SlackOpportunityPublisherTest {
private class RestMock implements HttpCalloutMock {
public HTTPResponse respond(HTTPRequest req) {
String fullJson = 'your Json Response';
HTTPResponse res = new HTTPResponse();
res.setHeader('Content-Type', 'text/json');
res.setBody(fullJson);
res.setStatusCode(200);
return res;
}
}
static testMethod void service_call() {
Test.setMock(HttpCalloutMock.class, new RestMock());
Test.startTest();
//your webserive call code
Database.GetUpdatedResult r =
Database.getUpdated(
'amount',
Datetime.now().addHours(-1),
Datetime.now());
Test.StopTest();
}
}
When I try to validate this in production it says it only gives me 68% coverage and I need 75%. Can someone help me write the test so that I can put into Prod?
Being new to salesforce i'm trying to make a prod deployment but it is failing because of code coverage issue.
These are the apex classes that i wrote:
HttpCallOut.apxc
public with sharing class HttpCallOut {
#future(callout=true)
public static void callService(string endpoint, string method, string body) {
try {
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint('callout:API_SERVICES' + endpoint);
request.setMethod(method);
request.setHeader('content-type', 'application/json');
request.setBody(body);
HttpResponse response = http.send(request);
if (response.getStatusCode() != 200) {
System.debug('The status code returned was not expected: ' + response.getStatusCode() + ' ' + response.getStatus() + ' ' + response.getBody());
throw new CustomException('Error calling endpoint ' + endpoint + 'Status Code: ' + response.getStatusCode() + 'Status: ' + response.getStatus()+ 'Response Body: ' + response.getStatus());
}
return;
} catch (CalloutException calloutException) {
throw new CustomException('Error in HttpCallOut callService: ', calloutException);
}
}
}
CustomException.Apxc
public class CustomException extends Exception {
}
HandleUpdateOnReturnRefundCase
public with sharing class HandleUpdateOnReturnRefundCase {
private HttpCallOut httpCallOut = new HttpCallOut();
#InvocableMethod
public static void handleUpdateOnReturnRefundCase(List<Id> caseIds) {
List<Case> updatedCases = [select id, Decision__c, ZoroCaseIdentifier__c, Type, Description, ReturnOptions__c from Case where Id in :caseIds];
Case updatedCase = updatedCases.get(0);
if((updatedCase.Decision__c == 'Approved' && updatedCase.ReturnOptions__c != null) || updatedCase.Decision__c == 'Rejected') {
httpCallOut.callService(
'/salesforce-case-updated',
'POST',
genPayload(updatedCase.id, updatedCase.ZoroCaseIdentifier__c, updatedCase.Type)
);
} else {
throw new CustomException('Cannot update the case, please fill all required fields');
}
update updatedCases;
}
private static String genPayload(Id caseId, String zoroCaseIdentifier, String caseType) {
CasePayload casePayload = new CasePayload();
casePayload.caseId = caseId;
casePayload.caseType = caseType;
casePayload.zoroCaseIdentifier = zoroCaseIdentifier;
return JSON.serialize(casePayload);
}
}
CasePayload.Apxc
public class CasePayload {
public Id caseId {
get { return caseId; }
set { caseId = value; }
}
public String zoroCaseIdentifier {
get { return zoroCaseIdentifier; }
set { zoroCaseIdentifier = value; }
}
public String caseType {
get { return caseType; }
set { caseType = value; }
}
}
For above apex classes i have written test cases:
HandleUpdateOnReturnRefundCaseTest
#isTest
private class HandleUpdateOnReturnRefundCaseTest {
static testMethod void testApprovedReturnRefundCase() {
Case mockCase = new Case();
mockCase.Type = 'Request Return';
insert mockCase;
Test.startTest();
Test.setMock(HttpCalloutMock.class, new HttpCalloutSuccessTest());
mockCase.Decision__c = 'Approved';
mockCase.ReturnOptions__c = 'FOC without Returned Items';
update mockCase;
Test.stopTest();
List<Case> cases = [SELECT Id, Decision__c FROM Case WHERE Id = :mockCase.Id];
for (Case c : cases) {
system.assertEquals(c.Decision__c, mockCase.Decision__c);
}
}
static testMethod void testRejectedReturnRefundCase() {
Case mockCase = new Case();
mockCase.Type = 'Request Return';
insert mockCase;
Test.startTest();
Test.setMock(HttpCalloutMock.class, new HttpCalloutSuccessTest());
mockCase.Decision__c = 'Rejected';
update mockCase;
Test.stopTest();
List<Case> cases = [SELECT Id, Decision__c FROM Case WHERE Id = :mockCase.Id];
for (Case c : cases) {
system.assertEquals(c.Decision__c, mockCase.Decision__c);
}
}
static testMethod void testCaseApprovedWithoutReturnOptions() {
try
{
Case mockCase = new Case();
mockCase.Type = 'Request Return';
insert mockCase;
Test.startTest();
Test.setMock(HttpCalloutMock.class, new HttpCalloutSuccessTest());
mockCase.Decision__c = 'Approved';
mockCase.ReturnOptions__c = null;
update mockCase;
Test.stopTest();
} catch (Exception e) {
System.assert(e.getMessage().contains('Please select Return Options before saving'), 'message=' + e.getMessage());
}
}
static testMethod void testCaseUpdatedWithHttpError() {
try
{
Case mockCase = new Case();
mockCase.Type = 'Request Return';
insert mockCase;
Test.startTest();
Test.setMock(HttpCalloutMock.class, new HttpCalloutErrorTest());
mockCase.Decision__c = 'Approved';
mockCase.ReturnOptions__c = 'FOC without Returned Items';
update mockCase;
Test.stopTest();
} catch (Exception e) {
System.assert(e.getMessage().contains('Error calling endpoint /salesforce-case-updated'), 'message=' + e.getMessage());
}
}
}
HttpCalloutSuccessTest
global class HttpCalloutSuccessTest implements HttpCalloutMock{
global HttpResponse respond(HTTPRequest req){
HttpResponse res = new HttpResponse();
res.setHeader('Content-Type', 'application/json');
res.setBody('{"status":"success"}');
res.setStatusCode(200);
return res;
}
}
HttpCalloutErrorTest
#isTest
global class HttpCalloutErrorTest implements HttpCalloutMock{
global HttpResponse respond(HTTPRequest req){
HttpResponse res = new HttpResponse();
res.setStatusCode(500);
return res;
}
}
When i run the test in sandbox by clicking "Run ALL Test" - i see that cove coverage is 92%. SO i made outbound set and tried to deploy to prod.
But in prod when i validated inbound change set it complained about code code coverage issue.
Not sure what i'm doing wrong? If test cases are missing then for which part of the code?
So tests passed, no exceptions, "just" code coverage problem? You included the tests in the changeset?
This looks like it's supposed to be called from a Flow/ProcessBuilder (InvocableMethod). Did you include that flow in package? Is it active? Or Case trigger (if it's called from trigger)
Or make the unit test call HandleUpdateOnReturnRefundCase.handleUpdateOnReturnRefundCase() directly, without "firing mechanism". It's an unit test, not a whole system integration. Test blocks independently and composition separately, will help you nail any errors.
If you still can't figure it out - refresh new sandbox, deploy to it (without unit test run) and continue working there, examine debug logs etc.
I have created an invocable method to run through Process builder. Although the class works when triggered with some changes, I get an error when running it through the process builder. From what I have determined, it is happening because the call out isn't run asynchronously.
That being said, I have tried to separate the classes and make one a future call out but I cannot figure out how to pass the three strings I have from the invocable class to my call out class.
Any help would be great!
public class SendText {
public class DataWrapper {
#InvocableVariable(label='Correspondence Name' required=true)
public String CorrespondenceName;
#InvocableVariable(label='Phone Number' required=true)
public String PhoneNumber;
#InvocableVariable(label='Text Message' required=true)
public String textMessage;
}
#InvocableMethod(label='Send Text Message')
public static void callSendTextMessage (List<DataWrapper> passedData) {
for (DataWrapper dw: passedData) {
//Basic Info needed to send request
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint('https://api.podium.com/api/v2/conversations');
request.setMethod('POST');
request.setHeader('Content-Type', 'application/json');
request.setHeader('Accept', 'application/json');
request.setHeader('Authorization', 'API Key');
//Create the 4 required fields for Podium
Map<String, String> message = new Map<String, String>{
'customerPhoneNumber' => dw.PhoneNumber,
'message' => dw.textMessage,
'locationId' => '49257',
'customerName' => dw.CorrespondenceName
};
String messageJson = JSON.serialize(message);
System.debug(messageJson);
request.setBody(messageJson);
HttpResponse response = http.send(request);
// Parse the JSON response
if (response.getStatusCode() != 201) {
System.debug('The status code returned was not expected: ' +
response.getStatusCode() + ' ' + response.getStatus());
} else {
System.debug(response.getBody());
}
}
}
}
Not sure if you tried Queueable Apex but this is how I do it, give this a shot:
public class SendText {
public class DataWrapper {
#InvocableVariable(label='Correspondence Name' required=true)
public String CorrespondenceName;
#InvocableVariable(label='Phone Number' required=true)
public String PhoneNumber;
#InvocableVariable(label='Text Message' required=true)
public String textMessage;
}
#InvocableMethod(label='Send Text Message')
public static void callSendTextMessage (List<DataWrapper> passedData) {
Id jobId = System.enqueueJob(new TextMessaeQueueable(passedData));
System.debug('Text messages job Id => ' + jobId);
}
private class TextMessaeQueueable implements Queueable, Database.AllowsCallouts {
private List<DataWrapper> wrappedData;
public TextMessaeQueueable(List<DataWrapper> passedData) {
this.wrappedData = passedData
}
public void execute(QueueableContext context) {
for (DataWrapper dw: this.wrappedData) {
//Basic Info needed to send request
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint('https://api.podium.com/api/v2/conversations');
request.setMethod('POST');
request.setHeader('Content-Type', 'application/json');
request.setHeader('Accept', 'application/json');
request.setHeader('Authorization', 'API Key');
//Create the 4 required fields for Podium
Map<String, String> message = new Map<String, String>{
'customerPhoneNumber' => dw.PhoneNumber,
'message' => dw.textMessage,
'locationId' => '49257',
'customerName' => dw.CorrespondenceName
};
String messageJson = JSON.serialize(message);
System.debug(messageJson);
request.setBody(messageJson);
HttpResponse response = http.send(request);
// Parse the JSON response
if (response.getStatusCode() != 201) {
System.debug('The status code returned was not expected: ' +
response.getStatusCode() + ' ' + response.getStatus());
} else {
System.debug(response.getBody());
}
}
}
}
}
I am getting following error while consuming "https://api.twitter.com/1/statuses/update.json?status=Test"
Steps followed:
Obtaining a request token - POST oauth / request_token
authorize
Converting the request token to an access token - POST oauth / access_token
got oauth_token and oauth_token_secret in step 3 response.
Now i want to use "https://api.twitter.com/1/statuses/update.json?status=Test" to tweet from salesforce to twitter, but getting following error:
response - System.HttpResponse[Status=Authorization Required, StatusCode=401]
response.getBody() - {"errors":[{"code":32,"message":"Could not authenticate you."}]}
OauthString = OAuth oauth_consumer_key="ILFzs0lcUiHwJsbpuWU4tTdk3",oauth_nonce="RElxMGNiWFJMOGp2V2VRcHB5aU96REhqYnVnbHZXc2o",oauth_signature="2aWbL3JASeSgNRaDQ%2BgLNXpH8dA%3D",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1466659830",oauth_token="743383838253002753-L4gdS3UCxKZVGTtQ0SHxSMlVtJREIBk",oauth_version="1.0"
Thanks in advance
Thanks,
Rahul
If you add more code which create and post tweet we could understand what's wrong faster. I can share with you APEX code which I use in my project for working with Twitter API:
public class SO2TP_TwitterUtil{
public static final String[] SIGNATURE_KEYS = new String[]{
'oauth_consumer_key',
'oauth_nonce',
'oauth_signature_method',
'oauth_timestamp',
'oauth_token',
'oauth_version',
'status'
};
public static final String[] OAUTH_KEYS = new String[]{
'oauth_consumer_key',
'oauth_nonce',
'oauth_signature',
'oauth_signature_method',
'oauth_timestamp',
'oauth_token',
'oauth_version'
};
public String algorithmName{
get{
if(algorithmName == null)
return 'hmacSHA1';
return algorithmName;
}
set;}
public String oauth_signature_method{
get{
if(oauth_signature_method == null)
return 'HMAC-SHA1';
return oauth_signature_method;
}
set;}
public String oauth_version{
get {
if(oauth_version == null)
oauth_version = '1.0';
return oauth_version;
}
set;}
public String http_method {get; set;}
public String base_url {get; set;}
public String status {get; set;}
public String oauth_consumer_key {get; set;}
public String oauth_consumer_secret {get; set;}
public String oauth_token {get; set;}
public String oauth_token_secret {get; set;}
public String oauth_nonce {get; private set;}
public String oauth_signature {get; private set;}
public String oauth_timestamp {
get {
if(oauth_timestamp == null)
oauth_timestamp = String.valueOf(DateTime.now().getTime()/1000);
return oauth_timestamp;
}
private set;}
private map<String, String> signaturePairs {get; set;}
private String parameterString {get; set;}
private String signatureBaseString {get; set;}
private String signingKey {get; set;}
private String oauth_header {get; set;}
private String http_body {get; set;}
public SO2TP_TwitterUtil () {}
public SO2TP_TwitterUtil(String oauth_consumer_key, String oauth_consumer_secret,
String oauth_token, String oauth_token_secret) {
this.oauth_consumer_key = oauth_consumer_key;
this.oauth_consumer_secret = oauth_consumer_secret;
this.oauth_token = oauth_token;
this.oauth_token_secret = oauth_token_secret;
}
public Boolean sendTweet(String status, map<String, String> additionalParams){
if(this.oauth_consumer_key == null ||
this.oauth_consumer_secret == null ||
this.oauth_token == null ||
this.oauth_token_secret == null)
return false;
this.http_method = 'POST';
this.base_url = 'https://api.twitter.com/1.1/statuses/update.json';
this.status = status;
generateNonce();
initializeSignatureKeyValuePairs(additionalParams);
generateOauthSignature();
generateOauthHeader();
generateHttpBody(additionalParams);
Http h = new Http();
HttpRequest req = new HttpRequest();
req.setMethod(this.http_method);
req.setEndpoint(this.base_url);
req.setBody(this.http_body);
req.setHeader('Content-Type', 'application/x-www-form-urlencoded');
req.setHeader('Content-Length', String.valueOf(req.getBody().length()));
req.setHeader('Authorization', this.oauth_header);
try {
HttpResponse res = h.send(req);
if(res.getStatusCode() == 200)
return true;
else
return false;
} catch (CalloutException e) {
return false;
}
return true;
}
private void generateNonce() {
String validChars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
Integer len = validChars.length();
String randomString = '';
for(Integer i=0; i<32; i++) {
Integer rInt = Integer.valueOf(Math.rint(Math.random()*(len-1)));
randomString += validChars.substring(rInt, rInt+1);
}
this.oauth_nonce = randomString;
}
private void initializeSignatureKeyValuePairs(map<String, String> additionalParams) {
this.signaturePairs = new map<String, String>();
this.signaturePairs.put('status', this.status);
this.signaturePairs.put('oauth_consumer_key', this.oauth_consumer_key);
this.signaturePairs.put('oauth_nonce', this.oauth_nonce);
this.signaturePairs.put('oauth_signature_method', this.oauth_signature_method);
this.signaturePairs.put('oauth_timestamp', this.oauth_timestamp);
this.signaturePairs.put('oauth_token', this.oauth_token);
this.signaturePairs.put('oauth_version', this.oauth_version);
if(additionalParams != null && additionalParams.keySet().size() > 0) {
for(String key : additionalParams.keySet()) {
if(!this.signaturePairs.containsKey(key) && additionalParams.get(key) != null) {
//system.debug('**** adding key: ' + key + ' and value: ' + additionalParams.get(key));
this.signaturePairs.put(key, additionalParams.get(key));
SIGNATURE_KEYS.add(key);
}
}
}
SIGNATURE_KEYS.sort();
}
private void generateOauthSignature() {
this.parameterString = createParameterString();
this.signatureBaseString = createSignatureBaseString();
this.signingKey = createSigningKey();
this.oauth_signature = createOauthSignature();
}
private String createParameterString() {
String paramString = '';
system.debug(json.serializepretty(signaturePairs));
for(String key : SIGNATURE_KEYS) {
paramString += SO2TP_StringUtil.percentEncode(key);
paramString += '=';
paramString += SO2TP_StringUtil.percentEncode(signaturePairs.get(key));
paramString += '&';
}
paramString = removeLastNLetters(paramString, 1);
system.debug('**** Parameter String');
system.debug(paramString);
return paramString;
}
private String createSignatureBaseString() {
String sigBase = '';
sigBase += this.http_method.toUpperCase() ;
sigBase += '&';
sigBase += SO2TP_StringUtil.percentEncode(this.base_url);
sigBase += '&';
sigBase += SO2TP_StringUtil.percentEncode(this.parameterString);
system.debug('**** Signature Base String');
system.debug(sigBase);
return sigBase;
}
private String createSigningKey() {
String signKey = SO2TP_StringUtil.percentEncode(this.oauth_consumer_secret);
signKey += '&';
signKey += SO2TP_StringUtil.percentEncode(this.oauth_token_secret);
system.debug('**** Signing Key');
system.debug(signKey);
return signKey;
}
private String createOauthSignature() {
Blob mac = Crypto.generateMac(this.algorithmName,
Blob.valueOf(this.signatureBaseString), Blob.valueOf(this.signingKey));
string hashedValue = EncodingUtil.convertToHex(mac);
String oauthSig = EncodingUtil.base64Encode(mac);
system.debug('**** Hashed Value');
system.debug(hashedValue);
system.debug('**** Oauth Signature');
system.debug(oauthSig);
return oauthSig;
}
private void generateOauthHeader() {
map<String, String> oauthParams = new map<String, String>();
oauthParams.put('oauth_consumer_key', this.oauth_consumer_key);
oauthParams.put('oauth_nonce', this.oauth_nonce);
oauthParams.put('oauth_signature', this.oauth_signature);
oauthParams.put('oauth_signature_method', this.oauth_signature_method);
oauthParams.put('oauth_timestamp', this.oauth_timestamp);
oauthParams.put('oauth_version', this.oauth_version);
oauthParams.put('oauth_token', this.oauth_token);
String header = 'OAuth ';
for(String key : OAUTH_KEYS) {
header += SO2TP_StringUtil.percentEncode(key);
header += '="';
header += SO2TP_StringUtil.percentEncode(oauthParams.get(key));
header += '", ';
}
this.oauth_header = removeLastNLetters(header, 2);
system.debug('**** Oauth Header');
system.debug(this.oauth_header);
}
private void generateHttpBody(map<String, String> additionalParams) {
String httpBody = 'status='+EncodingUtil.urlEncode(this.status, 'UTF-8');
if(additionalParams != null && additionalParams.keySet() != null) {
for(String key : additionalParams.keySet()) {
if(additionalParams.get(key) != null) {
httpBody += '&';
httpBody += EncodingUtil.urlEncode(key, 'UTF-8');
httpBody += '=';
httpBody += EncodingUtil.urlEncode(additionalParams.get(key), 'UTF-8');
}
}
}
this.http_body = httpBody.replace('*', '%2A');
system.debug('**** Request Body: ');
system.debug(this.http_body);
}
private static String removeLastNLetters(String source, Integer numToRemove) {
return source.subString(0, source.length()-numToRemove);
}
}
Please find my below code which is not working.
VF Page:
<apex:page controller="TestTwitterIntegrationController">
<apex:form >
<apex:commandButton value="OAuth" action="{!getAuthToken}" />
<br/>
<br/>
<apex:commandButton value="Tweet" action="{!tweetPost}" />
</apex:form>
Controller:
public class TestTwitterIntegrationController
{
public String testInput{get;set;}
final String oauthVersion = '1.0';
final String oauthConsumerKey = 'ILFzs0lcUiHwJsbpuWU4tTdk3';
final String oauthConsumerSecret = 'C3mxd7GpRzBs88WJeaXBcRFELdRyI56F7VZZIOiq74uXz3hJFi';
final String baseUrl = 'https://api.twitter.com';
final String oauthSignatureMethod = 'HMAC-SHA1';
final String oauth_callback = 'https://lightningdemo1492-dev-ed--rahullightning.ap2.visual.force.com/apex/TestTwitterIntegration';
String oauthTimestamp;
String oauthNonce;
String oauthToken;
String oauthTokenSecret;
String accessToken;
String accessTokenSecret;
String oauth_token;
String oauth_verifier;
public TestTwitterIntegrationController(){
this.oauth_token = ApexPages.currentPage().getParameters().get('oauth_token');
this.oauth_verifier = ApexPages.currentPage().getParameters().get('oauth_verifier');
/*Cookie counter = ApexPages.currentPage().getCookies().get('TSecret');
if(counter != null) {
this.oauthTokenSecret = counter.getValue();
ApexPages.currentPage().setCookies(new Cookie[]{new Cookie('TSecret', '', null, -1, false)});
}*/
}
private void getTimeStamp(){
DateTime dateTimeNow = dateTime.now();
this.oauthTimestamp = ''+(dateTimeNow.getTime()/1000);
}
private void generateNounce() {
final String chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
String randStr = '';
while (randStr.length() < 32) {
Integer idx = Math.mod(Math.abs(Crypto.getRandomInteger()), chars.length());
randStr += chars.substring(idx, idx+1);
}
this.oauthNonce = EncodingUtil.base64Encode(Blob.valueOf(randStr)).remove('=');
}
private String generateSignature(String httpMethod, String baseUrl, Map<String, String> params){
String encodedString = '';
Map<String, String> encodeParams = new Map<String, String>();
encodeParams.putAll(params);
encodeParams.put('oauth_nonce', this.oauthNonce);
encodeParams.put('oauth_signature_method', this.oauthSignatureMethod);
encodeParams.put('oauth_timestamp', this.oauthTimestamp);
encodeParams.put('oauth_consumer_key', this.oauthConsumerKey);
encodeParams.put('oauth_version', this.oauthVersion);
List<String> keyList = New List<String>();
keyList.addAll(encodeParams.keySet());
keyList.sort();
for(String key: keyList){
encodedString += EncodingUtil.urlEncode(key,'UTF-8') + '=' + EncodingUtil.urlEncode(encodeParams.get(key),'UTF-8') + '&';
}
encodedString = encodedString.removeEnd('&');
String baseString = httpMethod.toUpperCase() + '&' + EncodingUtil.urlEncode(baseUrl,'UTF-8') + '&' + EncodingUtil.urlEncode(encodedString,'UTF-8');
String signingKey = EncodingUtil.urlEncode(this.oauthConsumerSecret,'UTF-8') + '&';
if(params.containsKey('oauth_token') && String.isNotBlank(this.oauthTokenSecret)){
signingKey += EncodingUtil.urlEncode(this.oauthTokenSecret,'UTF-8');
}
system.debug('signingKey - '+signingKey);
Blob data = Crypto.generateMac('hmacSHA1', Blob.valueOf(baseString), Blob.valueOf(signingKey));
String signature = EncodingUtil.base64Encode(data);
system.debug('data - '+data);
system.debug('signature - '+signature);
return signature;
}
private String generateAuthHeader(Map<String, String> params){
Map<String, String> authParams = new Map<String, String>();
authParams.putAll(params);
authParams.put('oauth_consumer_key', this.oauthConsumerKey);
authParams.put('oauth_signature_method', this.oauthSignatureMethod);
authParams.put('oauth_timestamp', this.oauthTimestamp);
authParams.put('oauth_nonce', this.oauthNonce);
authParams.put('oauth_version', this.oauthVersion);
system.debug('authParams - '+authParams);
List<String> keyList = New List<String>();
keyList.addAll(authParams.keySet());
keyList.sort();
String OathString = '';
for(String key: keyList){
OathString += EncodingUtil.urlEncode(key,'UTF-8') + '=' + '"' + EncodingUtil.urlEncode(authParams.get(key),'UTF-8') + '"' + ', ';
}
OathString = 'OAuth ' + OathString.removeEnd(', ');
system.debug('OathString - '+OathString);
return OathString ;
}
public PageReference getAuthToken(){
String requestUrl = this.baseUrl + '/oauth/request_token';
String requestMethod = 'POST';
this.getTimeStamp();
this.generateNounce();
Map<String, String> params = new Map<String, String>();
params.put('oauth_callback', this.oauth_callback);
String authSignature = this.generateSignature(requestMethod, requestUrl, params);
params = new Map<String, String>();
params.put('oauth_callback',this.oauth_callback);
params.put('oauth_signature', authSignature);
HttpRequest request = new HttpRequest();
request.setHeader('Authorization', this.generateAuthHeader(params));
request.setMethod(requestMethod);
request.setEndpoint(requestUrl);
HttpResponse response = new HttpResponse();
this.oauthToken = '';
Http http = new Http();
response = http.send(request);
system.debug('response - '+response);
String responseBody = response.getBody();
this.oauthToken = responseBody.substringBefore('&').substringAfter('=');
system.debug('response.getBody() - '+response.getBody());
system.debug('oauthToken - '+oauthToken);
this.oauthTokenSecret = responseBody.substringAfter('&').substringBetween('=','&');
system.debug('oauthTokenSecret - '+oauthTokenSecret);
ApexPages.currentPage().setCookies(new Cookie[]{new Cookie('TSecret', oauthTokenSecret, null, -1, false)});
String finalRequestUrl = baseUrl + '/oauth/authorize?oauth_token=' + this.oauthtoken;
return new PageReference(finalRequestUrl).setRedirect(true);
}
public void tweetPost(){
this.oauthtoken = ApexPages.currentPage().getparameters().get('oauth_token');
if(String.isNotBlank(this.oauthtoken)){
String twitterId;
Cookie counter = ApexPages.currentPage().getCookies().get('TSecret');
if(counter != null) {
this.oauthTokenSecret = counter.getValue();
ApexPages.currentPage().setCookies(new Cookie[]{new Cookie('TSecret', '', null, -1, false)});
}
system.debug('this.oauthTokenSecret - '+this.oauthTokenSecret);
String requestUrl = this.baseUrl + '/oauth/access_token';
String httpMethod = 'POST';
String oauthVerifier = ApexPages.currentPage().getparameters().get('oauth_verifier');
this.getTimeStamp();
this.generateNounce();
Map<String, String> params = new Map<String, String>();
params.put('oauth_token', this.oauthToken);
params.put('oauth_verifier', oauthVerifier);
String authSignature = this.generateSignature(httpMethod, requestUrl, params);
params = new Map<String, String>();
params.put('oauth_token',this.oauthtoken);
params.put('oauth_signature',authSignature);
HttpRequest request = new HttpRequest();
HttpResponse response = new HttpResponse();
Http http = new Http();
request.setEndPoint(requestUrl);
request.setMethod(httpMethod);
request.setHeader('Authorization', this.generateAuthHeader(params));
request.setBody('oauth_verifier='+EncodingUtil.urlEncode(oauthVerifier, 'UTF-8'));
try{
response = http.send(request);
system.debug('response - '+response);
system.debug('response.getBody() - '+response.getBody());
String responseBody = response.getBody();
this.oauthToken = responseBody.substringBetween('oauth_token=', '&');
this.oauthTokenSecret = responseBody.substringBetween('oauth_token_secret=', '&');
system.debug('this.oauthToken - '+this.oauthToken);
system.debug('this.oauthTokenSecret - '+this.oauthTokenSecret);
twitterId = responseBody.substringBetween('user_id=', '&');
tweetPostMethod();
}catch(Exception e){
system.debug(e.getMessage());
}
}
}
public void tweetPostMethod(){
String requestUrl = 'https://api.twitter.com/1.1/statuses/update.json';
String requestMethod = 'POST';
this.getTimeStamp();
this.generateNounce();
Map<String, String> params = new Map<String, String>();
params.put('oauth_token', this.oauthToken);
params.put('status', 'TestFromSFDC123');
system.debug('tweetPostMethod | this.oauthToken - '+this.oauthToken);
system.debug('tweetPostMethod | this.oauthTokenSecret - '+this.oauthTokenSecret);
String authSignature = this.generateSignature(requestMethod, requestUrl, params);
params = new Map<String, String>();
params.put('oauth_token',this.oauthtoken);
params.put('oauth_signature',authSignature);
HttpRequest request = new HttpRequest();
request.setMethod(requestMethod);
request.setEndpoint(requestUrl);
String httpBody = 'status='+EncodingUtil.urlEncode('TestFromSFDC', 'UTF-8');
request.setBody(httpBody);
request.setBody(httpBody);
request.setHeader('Content-Type', 'application/x-www-form-urlencoded');
request.setHeader('Content-Length', String.valueOf(request.getBody().length()));
request.setHeader('Authorization', this.generateAuthHeader(params));
HttpResponse response = new HttpResponse();
Http http = new Http();
response = http.send(request);
system.debug('response - '+response);
system.debug('response.getBody() - '+response.getBody());
}
}
*Steps:
Click on "Oauth" button
Authorize app
Click on "Tweet" button
I am using Docusign API Integration to Salesforce. I have a requirement to update the data field tag in a document by calling the Docusign API from Salesforce after it has been sent for signature.
Let's say the routing order of signers are from signer 1 to signer 4. Initially the value of that data field tag will be null. After signer 3 "completed" his signature, I have to trigger the API call from Salesforce and update the tag with the value which is retrieved from custom field value of an object in Salesforce. Then Signer 4 will be able to see the value in the data field tag before he signs the document.
I used Merge fields for docusign to import the Salesforce data into that tag. But as I said before, initial value will be null (because the salesforce data of that merge field will also be null at that time) and I have to "halt" the signing process, update the tag and then continue to remaining signer.
Is there any way that I could "refresh" the envelope so that the value in the data field tag gets updated?
Will docusign allow to update the tag values in document with Salesforce data through API callouts after the envelope is sent?
Note that I have read the Modify tabs (tags) for Recipient article in Docusign RestAPI guide Version2. Is that for modifying tag types or tag values?
It is possible with Salesforce and DS but not the way you are going at it. I answered your question about background correct on the other question at Send (Load) a URL to web browser and run it in background in APEX
Merge fields are part of the question, but they are only shown as the value when "SENT" and update Salesforce only when the envelope is COMPLETED successfully, so really this is only a half solution for your scenario.
So here is what I have done for another DocuSign Client as a sample of how to do this, but please reach out to your DocuSign Account Manager as I think if you are doing these types of advanced workflows you could benifit from DocuSign's Profession Services Group which I am apart of.
1. Components added:
DocuSign Connect Object - dseRecipientConnectUpdate
custom Object - dseRecipientConnectUpdate__c
Trigger - dseRCU_AfterUpdate
Class - desController (in Sandbox and code below as well)
Class - CheckRecursive (in sandbox and code below as well)
DS Template Example -Agreement with ContractID 960BD14E-6A09-4A9E-89E6-77B1D8444B72
2. What you need yet to do
Replace Send on Behalf user with Sender of envelope via code (hard Coded as david.grigsby#docusign.com in code) lookup using envelopeID in DocuSign Status and get sender, then lookup in user that sender's email
Classify any stringified body's you want
Error Condition handling
Test Classes
Testing, Testing, testing
How I tested:
0. Turn on debugging for API user and Myself
a. Sent Envelope from Template
b. Signed the first three recipients
c. Code updated the dseRecipientConnectUpdate__c record (a36) that was the autoresponse blocking user aka just changed record by editing but no real change, then save.
d. It would then fire trigger again (as mentioned you will need to change the send on behalf of user to automatically for final code to be sending user, but you can make it your email you send envelope by) and it will read recipients, get the contract id recipient and tab, add new recipient and tab with value, delete old reciepents (tag recipient and blocking)
Salesforce Custom Object:
<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<!--actionoverrides removed for sake of SO answer size/>
<compactLayoutAssignment>SYSTEM</compactLayoutAssignment>
<deploymentStatus>Deployed</deploymentStatus>
<description>DocuSign Recipient Connect Update</description>
<enableActivities>true</enableActivities>
<enableFeeds>false</enableFeeds>
<enableHistory>true</enableHistory>
<enableReports>true</enableReports>
<fields>
<fullName>RecipStatus__c</fullName>
<externalId>false</externalId>
<label>RecipStatus</label>
<length>50</length>
<required>false</required>
<trackHistory>false</trackHistory>
<trackTrending>false</trackTrending>
<type>Text</type>
<unique>false</unique>
</fields>
<fields>
<fullName>RecipientEmail__c</fullName>
<description>Recipient Email</description>
<externalId>false</externalId>
<label>RecipientEmail</label>
<required>false</required>
<trackHistory>false</trackHistory>
<trackTrending>false</trackTrending>
<type>Email</type>
<unique>false</unique>
</fields>
<fields>
<fullName>RecipientID__c</fullName>
<externalId>false</externalId>
<label>RecipientID</label>
<length>50</length>
<required>false</required>
<trackHistory>false</trackHistory>
<trackTrending>false</trackTrending>
<type>Text</type>
<unique>false</unique>
</fields>
<fields>
<fullName>dsEnvelopeID__c</fullName>
<description>dsfs__DocuSign_Envelope_ID__c</description>
<externalId>false</externalId>
<label>dsEnvelopeID</label>
<length>56</length>
<required>false</required>
<trackHistory>false</trackHistory>
<trackTrending>false</trackTrending>
<type>Text</type>
<unique>false</unique>
</fields>
<label>dseRecipientConnectUpdate</label>
<listViews>
<fullName>All</fullName>
<filterScope>Everything</filterScope>
<label>All</label>
</listViews>
<nameField>
<displayFormat>dseRCU-{0000000000}</displayFormat>
<label>dseRecipientConnectUpdate Name</label>
<trackHistory>false</trackHistory>
<type>AutoNumber</type>
</nameField>
<pluralLabel>dseRecipientConnectUpdates</pluralLabel>
<recordTypeTrackHistory>false</recordTypeTrackHistory>
<recordTypes>
<fullName>dseRecipientConnectUpdate</fullName>
<active>true</active>
<description>dseRecipientConnectUpdate</description>
<label>dseRecipientConnectUpdate</label>
</recordTypes>
<searchLayouts/>
<sharingModel>ReadWrite</sharingModel>
</CustomObject>
Trigger
==========
trigger dseRCU_AfterUpdate on dseRecipientConnectUpdate__c (after update) {
try
{
if (CheckRecursive.runOnce())
{
List<dseRecipientConnectUpdate__c> myConnectUpdates = [Select d.dsEnvelopeID__c, d.RecipientID__c, d.RecipientEmail__c, d.RecipStatus__c, d.Id From dseRecipientConnectUpdate__c d WHERE Id IN:Trigger.newMap.keySet()];
for(dseRecipientConnectUpdate__c myConnectCompleted :myConnectUpdates)
{
system.debug(myConnectCompleted.Id);
if(myConnectCompleted.RecipStatus__c.indexOf('AutoResponded') != -1)
{
system.debug(myConnectCompleted.RecipStatus__c);
//Looking for bounce back user via status AutoResponded and #accelrys.com emails/recipients
if(myConnectCompleted.RecipientEmail__c.indexOf('invalidemail#baddomain.com') != -1)
{
//do modification to envelope here
dseController.updateEnvelope(myConnectCompleted.dsEnvelopeID__c, myConnectCompleted.RecipientID__c);
}
}
}
}
}
catch(Exception ex)
{
system.debug(ex);
}
finally
{
}
}
Class
==========
public with sharing class dseController {
public dseController()
{
}
public dseController(ApexPages.StandardController controller)
{
}
#future (callout=true)
public static void updateEnvelope( string envelopeID, string recipientID )
{
RecipientResponse RecipientResponseDeserialized = new RecipientResponse();
RecipientTabResponse RecipientTabResponseDeserialized = new RecipientTabResponse();
string rResponse = '{}';
string recipientGuidwithContractTab;
string recipientGuidForBlockingRecipient;
string rTabResponse = '{}';
string rSetRecipientResponse = '{}';
string rSetTabForRecipientResponse = '{}';
string rTabRecipientDeleteResponse = '{}';
string rBlockingRecipientDeleteResponse = '{}';
try
{
//Call to get envelope recipients
rResponse = getEnvelopeRecipients(envelopeID);
system.debug(rResponse);
RecipientResponseDeserialized = parseRecipentResponse(rResponse);
system.debug(RecipientResponseDeserialized);
recipientGuidwithContractTab = getRecipientwithContractTab(RecipientResponseDeserialized);
system.debug(recipientGuidwithContractTab);
//Call to get recipient tab
rTabResponse = getRecipientTab(envelopeID, recipientGuidwithContractTab);
system.debug(rTabResponse);
RecipientTabResponseDeserialized = parseRecipientTabResponse(rTabResponse);
system.debug(RecipientTabResponseDeserialized);
//Call to add recipient with new id
rSetRecipientResponse = setRecipientForNewTab(envelopeID,RecipientResponseDeserialized);
system.debug(rSetRecipientResponse);
//Call to add tab to new recipient with new id
rSetTabForRecipientResponse = setNewTabforNewRecipient(envelopeID,RecipientTabResponseDeserialized);
system.debug(rSetTabForRecipientResponse);
//Call to delete old clone recipient
rTabRecipientDeleteResponse = deleteRecipientTab(envelopeID, recipientGuidwithContractTab);
system.debug(rTabRecipientDeleteResponse);
//Call to delete blocking user
recipientGuidForBlockingRecipient = getBlockingRecipient(RecipientResponseDeserialized);
rBlockingRecipientDeleteResponse = deleteBlockingRecipient(envelopeID, recipientGuidForBlockingRecipient);
system.debug(rBlockingRecipientDeleteResponse);
}
catch(Exception ex)
{
system.debug(ex);
}
finally
{
}
}
public static string getRecipientwithContractTab(RecipientResponse rResponse)
{
string rContractTabID = 'Not Found';
try{
List<Signer> mySigners = rResponse.signers;
for(Signer mySigner : mySigners)
{
if(mySigner.roleName == 'ContractIDApprover')
{
rContractTabID = mySigner.recipientIdGuid;
}
}
}
catch(Exception ex)
{
system.debug(ex);
}
finally
{
}
return rContractTabID;
}
public static string getBlockingRecipient(RecipientResponse rResponse)
{
string rContractTabID = 'Not Found';
try{
List<Signer> mySigners = rResponse.signers;
for(Signer mySigner : mySigners)
{
if(mySigner.roleName == 'BlockingUser')
{
rContractTabID = mySigner.recipientIdGuid;
}
}
}
catch(Exception ex)
{
system.debug(ex);
}
finally
{
}
return rContractTabID;
}
public static string getEnvelopeRecipients(string envelopeID)
{
string response = '{}';
string DSEndpoint = 'https://demo.docusign.net/restapi/v2/';
string DSUserId = 'yourdsUserid';
string DSPassword = 'yourdspassword';
string DSAccountID = 'yourdsaccountID';
string DSIntegratorKey = 'yourdsintegratorkey';
try
{
//FORCES that the DocuSign member has to be in the DocuSign account DSFS is configured for
List<dsfs__DocuSignAccountConfiguration__c> dsAccountConfig = [Select d.dsfs__UseSendOnBehalfOf__c, d.dsfs__DocuSignBaseURL__c, d.dsfs__DSProSFUsername__c, d.dsfs__DSProSFPassword__c, d.dsfs__AccountId__c From dsfs__DocuSignAccountConfiguration__c d limit 1];
for(dsfs__DocuSignAccountConfiguration__c myConfig : dsAccountConfig)
{
DSEndpoint = myConfig.dsfs__DocuSignBaseURL__c + 'restapi/v2/';
DSUserId = myConfig.dsfs__DSProSFUsername__c;
DSPassword = myConfig.dsfs__DSProSFPassword__c;
}
HttpRequest request = new HttpRequest();
request.setEndpoint(DSEndpoint + 'accounts/'+DSAccountID+'/envelopes/'+envelopeID+'/recipients');
request.setMethod('GET');
request.setHeader('Content-Type', 'application/json');
request.setHeader('X-DocuSign-Authentication', '<DocuSignCredentials><Username>'+DSUserId+'</Username><Password>'+DSPassword+'</Password><IntegratorKey>'+DSIntegratorKey+'</IntegratorKey></DocuSignCredentials>');
request.setHeader('Accept', 'application/json');
request.setTimeout(120000);
system.debug(request.getHeader('X-DocuSign-Authentication'));
HttpResponse myResponse = (new Http()).send(request);
system.debug(myResponse.getBody());
if(myResponse.getStatusCode().format()=='200')
{
response = myResponse.getBody();
system.debug(response);
}
}
catch(Exception ex)
{
system.debug(ex);
}
finally
{
}
return response;
}
public static string getRecipientTab(string envelopeID, string recipientGuid)
{
string response = '{}';
string DSEndpoint = 'https://demo.docusign.net/restapi/v2/';
string DSUserId = 'yourdsUserid';
string DSPassword = 'yourdspassword';
string DSAccountID = 'yourdsaccountID';
string DSIntegratorKey = 'yourdsintegratorkey';
try
{
//FORCES that the DocuSign member has to be in the DocuSign account DSFS is configured for
List<dsfs__DocuSignAccountConfiguration__c> dsAccountConfig = [Select d.dsfs__UseSendOnBehalfOf__c, d.dsfs__DocuSignBaseURL__c, d.dsfs__DSProSFUsername__c, d.dsfs__DSProSFPassword__c, d.dsfs__AccountId__c From dsfs__DocuSignAccountConfiguration__c d limit 1];
for(dsfs__DocuSignAccountConfiguration__c myConfig : dsAccountConfig)
{
DSEndpoint = myConfig.dsfs__DocuSignBaseURL__c + 'restapi/v2/';
DSUserId = myConfig.dsfs__DSProSFUsername__c;
DSPassword = myConfig.dsfs__DSProSFPassword__c;
}
HttpRequest request = new HttpRequest();
request.setEndpoint(DSEndpoint + 'accounts/'+DSAccountID+'/envelopes/'+envelopeID+'/recipients/'+recipientGuid+'/tabs/');
request.setMethod('GET');
request.setHeader('Content-Type', 'application/json');
request.setHeader('X-DocuSign-Authentication', '<DocuSignCredentials><Username>'+DSUserId+'</Username><Password>'+DSPassword+'</Password><SendOnBehalfOf>david.grigsby#docusign.com</SendOnBehalfOf><IntegratorKey>'+DSIntegratorKey+'</IntegratorKey></DocuSignCredentials>');
request.setHeader('Accept', 'application/json');
request.setTimeout(120000);
system.debug(request.getHeader('X-DocuSign-Authentication'));
HttpResponse myResponse = (new Http()).send(request);
system.debug(myResponse.getBody());
if(myResponse.getStatusCode().format()=='200')
{
response = myResponse.getBody();
system.debug(response);
}
}
catch(Exception ex)
{
system.debug(ex);
}
finally
{
}
return response;
}
public static string setRecipientForNewTab(string envelopeID, RecipientResponse rResponse)
{
string response = '{}';
string DSEndpoint = 'https://demo.docusign.net/restapi/v2/';
string DSUserId = 'yourdsUserid';
string DSPassword = 'yourdspassword';
string DSAccountID = 'yourdsaccountID';
string DSIntegratorKey = 'yourdsintegratorkey';
try
{
//FORCES that the DocuSign member has to be in the DocuSign account DSFS is configured for
List<dsfs__DocuSignAccountConfiguration__c> dsAccountConfig = [Select d.dsfs__UseSendOnBehalfOf__c, d.dsfs__DocuSignBaseURL__c, d.dsfs__DSProSFUsername__c, d.dsfs__DSProSFPassword__c, d.dsfs__AccountId__c From dsfs__DocuSignAccountConfiguration__c d limit 1];
for(dsfs__DocuSignAccountConfiguration__c myConfig : dsAccountConfig)
{
DSEndpoint = myConfig.dsfs__DocuSignBaseURL__c + 'restapi/v2/';
DSUserId = myConfig.dsfs__DSProSFUsername__c;
DSPassword = myConfig.dsfs__DSProSFPassword__c;
}
Signer mySignerToAdd = new Signer();
List<Signer> mySigners = rResponse.signers;
for(Signer mySigner : mySigners)
{
if(mySigner.roleName == 'ContractIDApprover')
{
mySignerToAdd = mySigner;
}
}
String myBody;
myBody = '{"signers": [{"signInEachLocation": "false","name": "'+mySignerToAdd.name +'Added 1","email": "'+mySignerToAdd.email+'","recipientId": "7","requireIdLookup": "false","routingOrder": "19","roleName": "'+mySignerToAdd.roleName+'1"}]}';
HttpRequest request = new HttpRequest();
request.setEndpoint(DSEndpoint + 'accounts/'+DSAccountID+'/envelopes/'+envelopeID+'/recipients/');
request.setMethod('POST');
request.setHeader('Content-Type', 'application/json');
request.setHeader('X-DocuSign-Authentication', '<DocuSignCredentials><Username>'+DSUserId+'</Username><Password>'+DSPassword+'</Password><SendOnBehalfOf>david.grigsby#docusign.com</SendOnBehalfOf><IntegratorKey>'+DSIntegratorKey+'</IntegratorKey></DocuSignCredentials>');
request.setHeader('Accept', 'application/json');
request.setTimeout(120000);
request.setBody(myBody);
system.debug(request.getHeader('X-DocuSign-Authentication'));
HttpResponse myResponse = (new Http()).send(request);
system.debug(myResponse.getBody());
if(myResponse.getStatusCode().format()=='201')
{
response = myResponse.getBody();
system.debug(response);
}
}
catch(Exception ex)
{
system.debug(ex);
}
finally
{
}
return response;
}
public static string setNewTabforNewRecipient(string envelopeID, RecipientTabResponse rTabResponse)
{
string response = '{}';
string DSEndpoint = 'https://demo.docusign.net/restapi/v2/';
string DSUserId = 'yourdsUserid';
string DSPassword = 'yourdspassword';
string DSAccountID = 'yourdsaccountID';
string DSIntegratorKey = 'yourdsintegratorkey';
try
{
//FORCES that the DocuSign member has to be in the DocuSign account DSFS is configured for
List<dsfs__DocuSignAccountConfiguration__c> dsAccountConfig = [Select d.dsfs__UseSendOnBehalfOf__c, d.dsfs__DocuSignBaseURL__c, d.dsfs__DSProSFUsername__c, d.dsfs__DSProSFPassword__c, d.dsfs__AccountId__c From dsfs__DocuSignAccountConfiguration__c d limit 1];
for(dsfs__DocuSignAccountConfiguration__c myConfig : dsAccountConfig)
{
DSEndpoint = myConfig.dsfs__DocuSignBaseURL__c + 'restapi/v2/';
DSUserId = myConfig.dsfs__DSProSFUsername__c;
DSPassword = myConfig.dsfs__DSProSFPassword__c;
}
TextTabs myTextTabToAdd = new TextTabs();
List<TextTabs> myTextTabs = rTabResponse.textTabs;
for(TextTabs myTextTab : myTextTabs)
{
if(myTextTab.tabLabel == 'ContractID')
{
myTextTabToAdd = myTextTab;
}
}
String myBody;
myBody = '{"textTabs": [{"height": '+myTextTabToAdd.height+',"shared": "'+myTextTabToAdd.shared+'","requireInitialOnSharedChange": "'+myTextTabToAdd.requireInitialOnSharedChange+'","name": "'+myTextTabToAdd.name+'1","value": "ContractID12345","width": '+myTextTabToAdd.width+',"required": "'+myTextTabToAdd.required+'","locked": "'+myTextTabToAdd.locked+'","concealValueOnDocument": "'+myTextTabToAdd.concealValueOnDocument+'","disableAutoSize": "'+myTextTabToAdd.disableAutoSize+'","tabLabel": "'+myTextTabToAdd.tabLabel+'","documentId": "'+myTextTabToAdd.documentId+'","recipientId": "7","pageNumber": "'+myTextTabToAdd.pageNumber+'","xPosition": "'+myTextTabToAdd.xPosition+'","yPosition": "'+myTextTabToAdd.yPosition+'"}]}';
HttpRequest request = new HttpRequest();
request.setEndpoint(DSEndpoint + 'accounts/'+DSAccountID+'/envelopes/'+envelopeID+'/recipients/7/tabs');
request.setMethod('POST');
request.setHeader('Content-Type', 'application/json');
request.setHeader('X-DocuSign-Authentication', '<DocuSignCredentials><Username>'+DSUserId+'</Username><Password>'+DSPassword+'</Password><SendOnBehalfOf>david.grigsby#docusign.com</SendOnBehalfOf><IntegratorKey>'+DSIntegratorKey+'</IntegratorKey></DocuSignCredentials>');
request.setHeader('Accept', 'application/json');
request.setTimeout(120000);
request.setBody(myBody);
system.debug(request.getHeader('X-DocuSign-Authentication'));
HttpResponse myResponse = (new Http()).send(request);
system.debug(myResponse.getBody());
if(myResponse.getStatusCode().format()=='201')
{
response = myResponse.getBody();
system.debug(response);
}
}
catch(Exception ex)
{
system.debug(ex);
}
finally
{
}
return response;
}
public static string deleteRecipientTab(string envelopeID, string recipientGuid)
{
string response = '{}';
string DSEndpoint = 'https://demo.docusign.net/restapi/v2/';
string DSUserId = 'yourdsUserid';
string DSPassword = 'yourdspassword';
string DSAccountID = 'yourdsaccountID';
string DSIntegratorKey = 'yourdsintegratorkey';
try
{
//FORCES that the DocuSign member has to be in the DocuSign account DSFS is configured for
List<dsfs__DocuSignAccountConfiguration__c> dsAccountConfig = [Select d.dsfs__UseSendOnBehalfOf__c, d.dsfs__DocuSignBaseURL__c, d.dsfs__DSProSFUsername__c, d.dsfs__DSProSFPassword__c, d.dsfs__AccountId__c From dsfs__DocuSignAccountConfiguration__c d limit 1];
for(dsfs__DocuSignAccountConfiguration__c myConfig : dsAccountConfig)
{
DSEndpoint = myConfig.dsfs__DocuSignBaseURL__c + 'restapi/v2/';
DSUserId = myConfig.dsfs__DSProSFUsername__c;
DSPassword = myConfig.dsfs__DSProSFPassword__c;
}
HttpRequest request = new HttpRequest();
request.setEndpoint(DSEndpoint + 'accounts/'+DSAccountID+'/envelopes/'+envelopeID+'/recipients/'+recipientGuid);
request.setMethod('DELETE');
request.setHeader('Content-Type', 'application/json');
request.setHeader('X-DocuSign-Authentication', '<DocuSignCredentials><Username>'+DSUserId+'</Username><Password>'+DSPassword+'</Password><SendOnBehalfOf>youremail#yourdomain.com</SendOnBehalfOf><IntegratorKey>'+DSIntegratorKey+'</IntegratorKey></DocuSignCredentials>');
request.setHeader('Accept', 'application/json');
request.setTimeout(120000);
system.debug(request.getHeader('X-DocuSign-Authentication'));
HttpResponse myResponse = (new Http()).send(request);
system.debug(myResponse.getBody());
if(myResponse.getStatusCode().format()=='200')
{
response = myResponse.getBody();
system.debug(response);
}
}
catch(Exception ex)
{
system.debug(ex);
}
finally
{
}
return response;
}
public static string deleteBlockingRecipient(string envelopeID, string recipientGuid)
{
string response = '{}';
string DSEndpoint = 'https://demo.docusign.net/restapi/v2/';
string DSUserId = 'yourdsUserid';
string DSPassword = 'yourdspassword';
string DSAccountID = 'yourdsaccountID';
string DSIntegratorKey = 'yourdsintegratorkey';
try
{
//FORCES that the DocuSign member has to be in the DocuSign account DSFS is configured for
List<dsfs__DocuSignAccountConfiguration__c> dsAccountConfig = [Select d.dsfs__UseSendOnBehalfOf__c, d.dsfs__DocuSignBaseURL__c, d.dsfs__DSProSFUsername__c, d.dsfs__DSProSFPassword__c, d.dsfs__AccountId__c From dsfs__DocuSignAccountConfiguration__c d limit 1];
for(dsfs__DocuSignAccountConfiguration__c myConfig : dsAccountConfig)
{
DSEndpoint = myConfig.dsfs__DocuSignBaseURL__c + 'restapi/v2/';
DSUserId = myConfig.dsfs__DSProSFUsername__c;
DSPassword = myConfig.dsfs__DSProSFPassword__c;
}
HttpRequest request = new HttpRequest();
request.setEndpoint(DSEndpoint + 'accounts/'+DSAccountID+'/envelopes/'+envelopeID+'/recipients/'+recipientGuid);
request.setMethod('DELETE');
request.setHeader('Content-Type', 'application/json');
request.setHeader('X-DocuSign-Authentication', '<DocuSignCredentials><Username>'+DSUserId+'</Username><Password>'+DSPassword+'</Password><SendOnBehalfOf>youremail#yourdomain.com</SendOnBehalfOf><IntegratorKey>'+DSIntegratorKey+'</IntegratorKey></DocuSignCredentials>');
request.setHeader('Accept', 'application/json');
request.setTimeout(120000);
system.debug(request.getHeader('X-DocuSign-Authentication'));
HttpResponse myResponse = (new Http()).send(request);
system.debug(myResponse.getBody());
if(myResponse.getStatusCode().format()=='200')
{
response = myResponse.getBody();
system.debug(response);
}
}
catch(Exception ex)
{
system.debug(ex);
}
finally
{
}
return response;
}
public static RecipientResponse parseRecipentResponse(String json) {
return (RecipientResponse) System.JSON.deserialize(json, RecipientResponse.class);
}
public static RecipientTabResponse parseRecipientTabResponse(String json) {
return (RecipientTabResponse) System.JSON.deserialize(json, RecipientTabResponse.class);
}
public class Signer
{
public string name;
public string email;
public string recipientId;
public string recipientIdGuid;
public string requireIdLookup;
public string userId;
public string routingOrder;
public string roleName;
public string status;
public string signedDateTime;
public string deliveredDateTime;
public string templateLocked;
public string templateRequired;
}
public class RecipientResponse
{
public List<Signer> signers;
public List<Signer> agents;
public List<Signer> editors;
public List<Signer> intermediaries;
public List<Signer> carbonCopies;
public List<Signer> certifiedDeliveries;
public List<Signer> inPersonSigners;
public String recipientCount;
public String currentRoutingOrder;
}
public class TextTabs {
public Integer height;
public String validationPattern;
public String validationMessage;
public String shared;
public String requireInitialOnSharedChange;
public String name;
public String value;
public Integer width;
public String required;
public String locked;
public String concealValueOnDocument;
public String disableAutoSize;
public String tabLabel;
public String documentId;
public String recipientId;
public String pageNumber;
public String xPosition;
public String yPosition;
public String tabId;
}
public class RecipientTabResponse
{
public List<TextTabs> textTabs;
}
}