Salesforce DocuSign Integration - salesforce

Use Case - Salesforce Docusign implementation:
We have Parent and child object in salesforce where Parent have authorize signer and Relationship Manger email information and their each child object have document which we need to sign by authorize signer and relationship manger.
We need to send all the child object documents in single envelope. And when the signing ceremony completed we need to attach respective signed documents to their respective child records.
Currently, we can planning to do through Apex Toolkit or DocuSign rest API.
Example: Authorized signer and RM present on account record. And each contact associated with account having document which are attached by Contact person. Account owner should have button where it should fetch all the document from related contact, create envelope, should tagging the signature on each document and able to send to authorized Signer and RM.
Authorized Signer should received all the document with in single envelope. They signed all the document. Once Signed by them all the signed document should go back to respective contact.
Note: Business wants to see all the Recipients status and document sent to end user in salesforce as well.
Can you please provide input on this and share some sample as per our use case?

The flow here would be to pull the documents with DocumentService.getLinkedDocuments and then set up anchor tabs. If you want to send multiple documents, you'll need to set the Anchor Population Scope to Document. If docs are numbered in the order of the list 1, 2, 3. You will use .withOptions for the writeBack. Example can be found here:
https://www.docusign.com/blog/developers/whats-new-summer-21-apex-toolkit
And a sample code (except for the writeback part):
//Find your contact to add
Contact myContact = [SELECT Id, Name, Email FROM Contact WHERE Name = 'Snow Beard' LIMIT 1];
//This sets tab as an anchor tab. If using this with multiple documents,
// Ask customer support to set Account Setting Anchor Population Scope to Document.
dfsle.Tab hereTab = new dfsle.SignHereTab()
.withScale(1) // 1/2 scale
.withRequired(true) // Signing mandatory
.withDataLabel('SignHereMeHardy')
.withAnchor(
new dfsle.Tab.Anchor(
'Anchor1', // Anchor string
true, // allow white space in anchor string
true, // Anchor string is not case sensitive
'right', // Horizontal alignment in relation to the anchor text
true, // Ignore if the anchor text is not present in the document
true, // Must match the value of the anchor string in its entirety
'pixels', // Unit of the x and y offset properties
10, // X offset
10 // Y offset
)
)
//This places the tab on the first docunent in the list on page one. Requires DocuSign Support to set Anchor Population Scope to Document.
.withPosition(
new dfsle.Tab.Position(
1, //Document id matches order of documents
1, //Page id
null,
null,
20,
20
)
);
//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 if using a template or use Default 'Signer 1'
new dfsle.Entity(myContact.Id) //source object for the Recipient
)
.withTabs(new List<dfsle.Tab> { // Associate the tabs with this recipient
hereTab
});
Opportunity myOpportunity = [SELECT Id FROM Opportunity WHERE Name = 'Sailcloth' LIMIT 1];
//This pulls all the documents from the Opportunity Object and adds them to documents list
List<dfsle.Document> documents = dfsle.DocumentService.getLinkedDocuments
(
ContentVersion.getSObjectType(),
new Set<Id>{myOpportunity.Id},
false
);
// Create an empty envelope.
// This shows how to pull documents from an object in Salesforce. In this case an Opportunity
dfsle.Envelope myEnvelope = dfsle.EnvelopeService.getEmptyEnvelope(new dfsle.Entity(myOpportunity.Id))
.withRecipients(new List<dfsle.Recipient> { myRecipient })
.withDocuments(documents);
// Send the envelope
try {
dfsle.EnvelopeService.sendEnvelope(myEnvelope, true);
} catch (dfsle.APIException ex) {
system.debug(ex);
if (ex.error.code == dfsle.APIErrorCode.CONSENT_REQUIRED) {
// user is a valid member of the DocuSign account, but has not granted consent to this application
} else {
// handle other errors
}
}

Related

How to generate DocuSign embedded signing url from apex?

I want to generate the DocuSign embedded URL to get the documents signed by the community user.
I am able to achieve the requirement. Here is the solution
Initial things
DocuSign setup from both sides (Salesforce and DocuSign itself).
Signing user must be assigned “DocuSign Sender” permission set to sign the
document(s).
Create and send an envelope – First method
public static String sendEnvelope(String recordId) {
Id mySourceId = recordId; // The ID of the initiating Salesforce object
// Create an empty envelope and add a Salesforce Document and embedded signer
recipient
// The embedded signer will be the current user with sequence and routing
order 1 and role "Signer 1" by default
List<dfsle.Document> myDocuments = new List<dfsle.Document>();
// Content Version need to be param or queried
myDocuments =
dfsle.DocumentService.getDocuments(ContentVersion.getSObjectType(),
new Set<Id> { ContentVersionId(s) });
dfsle.Envelope dsEnvelope = dfsle.EnvelopeService.getEmptyEnvelope(
new dfsle.Entity(mySourceId))//The initiating Salesforce entity current SF user
.withDocuments(myDocuments)
.withRecipients(new List<dfsle.Recipient> {
dfsle.Recipient.newEmbeddedSigner() // An embedded signer
}
);
// Send the envelope.
dsEnvelope = dfsle.EnvelopeService.sendEnvelope(
dsEnvelope, // The envelope to send
true // Send now?
);
// Return string value of DocuSign envelope ID
return String.valueOf(dsEnvelope.docuSignId);
}
Host an embedded signing session – second method
// passing envId as parameter that we will receive from above method
public static String getEmbeddedSigningUrl(String envId) {
// url will be redirect URL
Url mySigningUrl = dfsle.SigningService.getEmbeddedSigningUrl(
dfsle.UUID.parse(envId), // envId value as a UUID
new URL(url) // url value as a URL
);
// Return string value of url to controller
return mySigningUrl.toExternalForm();
}
Variable Source id – It is the parent object record id where we want to store the signed documents back into salesforce.
Set of content version ids which are stored as files with s1,d1 tags etc.
myDocuments =
dfsle.DocumentService.getDocuments(ContentVersion.getSObjectType(),
new Set<Id> { ContentVersionId(s) });
Redirect URL - After signing the document(s) where we want to redirect the user.
In the case of using DocuSign in the context of Community user
Note: In the DocuSign Setup tab choose Configuration in the left menu, then go to the Settings tab and choose a user next to Enable System sender. This allows Community users to send envelopes even if they are not a member of the DocuSign account. In that case, envelopes will be sent from the admin user that you selected.
Important Points to remember
Embedded URL is valid only for 5 mins by default, if we want to increase the time
we will have to talk to the DocuSign support team and it can be increased max up
to 15 mins depending on the service plan.
References
https://developers.docusign.com/docs/salesforce/how-to/embedded-sending-signing/

How to get user id, and user UUID/GUID from Keycloak?

I'm using Keycloak inside docer and hosted on https://accounts.example.com.
I'm using React as my client library and after login, user goes into https://user.example.com.
This React client uses .NET Core API located at https://api.user.example.com.
I use keycloak.js to manage access in React panel.
Now let's say user wants to create a ticket. I send this ticket info to the API:
{
title: 'Urgent backup',
priority: 'urgent',
description: 'Please backup my files immediately'
}
In our database, we have this design:
create table Tickets
(
Id bigint not null primary identity(1, 1),
UserGuid uniqueidentifier not null, -- How should I fill this column?
Title nvarchar(200) not null,
PriorityId int not null,
Description nvarchar(max) not null
)
The problem is, API should extract a permanent data from user.
I can't store email or username in that column of course. And I can't even rely on username or email because Keycloak's admin panel allows this setting to be configured:
Thus the best option is to give user a GUID or UUID in Keycloak, and retrieve it in open id token.
I searched but I can't find how to do this.
Can you help?
By default your acccess token should have a subject (sub) claim with a value of the user's id in Keycloak. That is a UUID.
You can extract that ID from the token and use it.
Maybe ASP.NET core will do this automatically and provide the subject claim as the username for you.
I am not sure where exactly is the issue ,Keycloak already provide the API to get/update/delete user
Get users Returns a list of users, filtered according to query parameters:
GET /{realm}/users
In Query Parameters you can filter according to email/first/lastName/username
and it will give result something like this if you want to fetch all user
[
{
"id":"569f67de-36e6-4552-ac54-e52085109818",
"username":"user1",
"enabled":true,
...
},
{
"id":"90afb701-fae5-40b4-8895-e387ba34902jh",
"username":"user2",
"enabled":true,
....
}
]
If you want to fetch individual user ,you can get it that also with below API
GET /{realm}/users/{id}
If you see the first rest query ,you can query as per your requirement with Query Parameters and get the result and then id can be use for your second table.
Edit -
By default, the User ID can be obtained directly from the principal
String userId = accessToken.getSubject();
in .Net Core I found this
public static T GetLoggedInUserId<T>(this ClaimsPrincipal principal)
{
if (principal == null)
throw new ArgumentNullException(nameof(principal));
var loggedInUserId = principal.FindFirstValue(ClaimTypes.NameIdentifier);
if (typeof(T) == typeof(string))
{
return (T)Convert.ChangeType(loggedInUserId, typeof(T));
}
else if (typeof(T) == typeof(int) || typeof(T) == typeof(long))
{
return loggedInUserId != null ? (T)Convert.ChangeType(loggedInUserId, typeof(T)) : (T)Convert.ChangeType(0, typeof(T));
}
else
{
throw new Exception("Invalid type provided");
}
}

Integration Salesforce with Docusign Invalid type: dfsle.Envelope

I'm trying to integrate the Salesforce with DocuSign with Docusign Apex Toolkit, but dfsle class is not available in my org. I installed the Apex Tool Kit (https://developers.docusign.com/docs/salesforce/how-to/apex-toolkit-install/)
Id MySourceId = '00Q0m00000884XXXXX';
dfsle.Envelope myEnvelope = dfsle.EnvelopeService.getEmptyEnvelope(new dfsle.Entity(mySourceId));
Lead myContact = [SELECT Id, Name, Email FROM lead where id = '00Q0m00000884XXXX'];
//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
dfsle.UUID myTemplateId = dfsle.UUID.parse('28386dbc-2576-4637-bb77-c86938fe080f');
//create a new document for the Envelope
dfsle.Document myDocument = dfsle.Document.fromTemplate(
myTemplateId, // templateId in dfsle.UUID format
'Self Sales Teste'); // name of the template
// Send the envelope.
myEnvelope = dfsle.EnvelopeService.sendEnvelope(
myEnvelope, // The envelope to send
true); // Send now?
try {
dfsle.EnvelopeService.sendEnvelope(envelope, true);
} catch (dfsle.APIException ex) {
if (ex.error.code == dfsle.APIErrorCode.CONSENT_REQUIRED) {
// user is a valid member of the DocuSign account, but has not granted consent to this application
} else {
// handle other errors
}
}
Error: Line: 3, Column: 1
Error: Invalid type: dfsle.Envelope
Have same issue few weeks ago :) Go to your Salesforce Setup. Type Installed Packages in quick find box. Make sure the DocuSign App Launcher is installed. Check package prefix.

Send Salesforce Attachment with Docusign

I'm trying to use DocuSign API in Salesforce (apex code) to send an envelope with the document.
It is working when using templateid that was setup in my DocuSign sandbox, but I want to use Salesforce attachment that related to the record, and I'm getting an exception
dfsle.DocuSignException: Unable to read content for documents: Disti1234B.pdf (001f400000za2c9AAA).
Any idea why I'm getting it?
Note that I tried using in SF both Attachment and File, but got the same error in both.
Trace:
FATAL_ERROR Class.dfsle.EnvelopeAPI: line 1027, column 1
Class.dfsle.EnvelopeAPI.APIEnvelope.<init>: line 1065, column 1
Class.dfsle.EnvelopeAPI.createEnvelope: line 1155, column 1
Class.dfsle.EnvelopeAPI.createEnvelope: line 1144, column 1
Class.dfsle.EnvelopeService.sendEnvelope: line 641, column 1
Class.dfsle.EnvelopeService.sendEnvelope: line 607, column 1
Code script:
Id accountId = '001f400000za2c9'; // The ID of the initiating Salesforce object.
// Create an empty envelope.
dfsle.Envelope myEnvelope = dfsle.EnvelopeService.getEmptyEnvelope(new dfsle.Entity(accountId));
//we will use a Salesforce contact record as a Recipient here
Contact myContact = [SELECT Id, Name, Email FROM Contact where Id = '003f400001Gk49f'];
//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
//add Recipient to the Envelope
myEnvelope = myEnvelope.withRecipients(new List<dfsle.Recipient> { myRecipient });
/*WITH TEMPLATE ID IT IS WORKING FINE
//myTemplateId contains the DocuSign Id of the DocuSign Template
dfsle.UUID myTemplateId = dfsle.UUID.parse('f4252788-0799-4786-bac4-7c6a3f1d37a8');
//create a new document for the Envelope
dfsle.Document myDocument = dfsle.Document.fromTemplate(
myTemplateId, // templateId in dfsle.UUID format
'myTemplate'); // name of the template
*/
Attachment att = [SELECT Id, Name, Body, ContentType,LastModifiedDate,BodyLength FROM Attachment WHERE Id = '00Pf400000KPKBh'];
dfsle.Document myDocument = new dfsle.Document(att.Id, 'File', 1, att.Name, 'pdf', att.BodyLength, att.LastModifiedDate, accountId);
//add document to the Envelope
myEnvelope = myEnvelope.withDocuments(new List<dfsle.Document> { myDocument });
myEnvelope = dfsle.EnvelopeService.sendEnvelope(myEnvelope, true);
Still not sure why it is happened, but I was able to get it work by using the following method:
list<dfsle.Document> l_doc = dfsle.DocumentService.getDocuments(ContentVersion.getSObjectType(), new set<Id>{'068f400000EFNuaAAH'});
Note that according to docusign documentation it is working only with documents (File in salesforce), it is not working with Salesforce Attachment

Adding Custom Attributes to Firebase Auth

I have hunted through Firebase's docs and can't seem to find a way to add custom attributes to FIRAuth. I am migrating an app from Parse-Server and I know that I could set a user's username, email, and objectId. No I see that I have the option for email, displayName, and photoURL. I want to be able to add custom attributes like the user's name. For example, I can use:
let user = FIRAuth.auth()?.currentUser
if let user = user {
let changeRequest = user.profileChangeRequest()
changeRequest.displayName = "Jane Q. User"
changeRequest.photoURL =
NSURL(string: "https://example.com/jane-q-user/profile.jpg")
changeRequest.setValue("Test1Name", forKey: "usersName")
changeRequest.commitChangesWithCompletion { error in
if error != nil {
print("\(error!.code): \(error!.localizedDescription)")
} else {
print("User's Display Name: \(user.displayName!)")
print("User's Name: \(user.valueForKey("name"))")
}
}
}
When I run the code, I get an error that "usersName" is not key value compliant. Is this not the right code to use. I can't seem to find another way.
You can't add custom attributes to Firebase Auth. Default attributes have been made available to facilitate access to user information, especially when using a provider (such as Facebook).
If you need to store more information about a user, use the Firebase realtime database. I recommend having a "Users" parent, that will hold all the User children. Also, have a userId key or an email key in order to identify the users and associate them with their respective accounts.
Hope this helps.
While in most cases you cannot add custom information to a user, there are cases where you can.
If you are creating or modifying users using the Admin SDK, you may create custom claims. These custom claims can be used within your client by accessing attributes of the claims object.
Swift code from the Firebase documentation:
user.getIDTokenResult(completion: { (result, error) in
guard let admin = result?.claims?["admin"] as? NSNumber else {
// Show regular user UI.
showRegularUI()
return
}
if admin.boolValue {
// Show admin UI.
showAdminUI()
} else {
// Show regular user UI.
showRegularUI()
}
})
Node.js code for adding the claim:
// Set admin privilege on the user corresponding to uid.
admin.auth().setCustomUserClaims(uid, {admin: true}).then(() => {
// The new custom claims will propagate to the user's ID token the
// next time a new one is issued.
});

Resources