feat: add recipient resolution from Client_Case__c lookup fields

- Queries Client_Case__c for Service_Coordinator__c and Docusign_Recipient_1__c
- Resolves Contact/User name and email from lookup targets
- Maps recipients to Docusign template roles: 'Service Coordinator' and 'Docusign Recipient #1'
- Validates recipients exist and have email addresses
- Supports both Contact and User lookup types
- Role names and field names are configurable constants at top of class
- Clear error messages if recipients are missing or have no email
This commit is contained in:
Paul Huliganga 2026-02-25 12:28:08 -05:00
parent 4b1edd4d27
commit 4211648e2a
1 changed files with 102 additions and 5 deletions

View File

@ -1,11 +1,25 @@
/**
* @description Combines multiple Docusign templates into a single composite envelope
* using the dfsle Apex Toolkit (Docusign for Salesforce managed package)
* using the dfsle Apex Toolkit (Docusign for Salesforce managed package).
* Recipients are resolved from Client_Case__c lookup fields.
* @author Paul Huliganga
* @date 2026-02-25
*/
global with sharing class DocusignCompositeEnvelopeBuilder {
// ============================================================
// CONFIGURATION: Update these constants if field/role names change
// ============================================================
// API names of the lookup fields on Client_Case__c that point to recipient records
// These are the "Select Lookup Field" values from the Docusign template recipient config
private static final String FIELD_SERVICE_COORDINATOR = 'Service_Coordinator__c';
private static final String FIELD_DOCUSIGN_RECIPIENT = 'Docusign_Recipient_1__c';
// Role names must match EXACTLY what's configured in the Docusign templates
private static final String ROLE_SERVICE_COORDINATOR = 'Service Coordinator';
private static final String ROLE_DOCUSIGN_RECIPIENT = 'Docusign Recipient #1';
@InvocableMethod(
label='Send Composite Docusign Envelope'
description='Combines multiple Docusign templates into a single envelope using dfsle Apex Toolkit'
@ -25,7 +39,7 @@ global with sharing class DocusignCompositeEnvelopeBuilder {
// Validate request
DocusignEnvelopeRequestHandler.validateRequest(req);
// Create empty envelope linked to the source Salesforce record
// Create empty envelope linked to the source record
dfsle.Envelope myEnvelope = dfsle.EnvelopeService.getEmptyEnvelope(
new dfsle.Entity(req.recordId)
);
@ -43,16 +57,18 @@ global with sharing class DocusignCompositeEnvelopeBuilder {
)
);
}
// Add all templates as documents to the envelope
myEnvelope = myEnvelope.withDocuments(documents);
// Resolve recipients from Client_Case__c lookup fields
List<dfsle.Recipient> recipients = resolveRecipients(req.recordId);
myEnvelope = myEnvelope.withRecipients(recipients);
// Set email subject if provided
if (String.isNotBlank(req.emailSubject)) {
myEnvelope = myEnvelope.withEmail(req.emailSubject, '');
}
// Send the envelope (true = send immediately)
// Send the envelope
myEnvelope = dfsle.EnvelopeService.sendEnvelope(myEnvelope, true);
// Success
@ -82,6 +98,87 @@ global with sharing class DocusignCompositeEnvelopeBuilder {
return results;
}
/**
* @description Resolves recipients from Client_Case__c lookup fields.
* Queries the case record and related contacts to get name/email.
* @param recordId The Client_Case__c record ID
* @return List of dfsle.Recipient objects with role mappings
*/
private static List<dfsle.Recipient> resolveRecipients(String recordId) {
// Query the Client_Case__c record with recipient lookup fields
// NOTE: Adjust field API names if they differ in your org
String query = 'SELECT Id, '
+ FIELD_SERVICE_COORDINATOR + ', '
+ FIELD_DOCUSIGN_RECIPIENT
+ ' FROM Client_Case__c WHERE Id = :recordId LIMIT 1';
Client_Case__c caseRecord = Database.query(query);
List<dfsle.Recipient> recipients = new List<dfsle.Recipient>();
Integer routingOrder = 1;
// Recipient 1: Service Coordinator
Id serviceCoordinatorId = (Id) caseRecord.get(FIELD_SERVICE_COORDINATOR);
if (serviceCoordinatorId != null) {
recipients.add(buildRecipient(serviceCoordinatorId, ROLE_SERVICE_COORDINATOR, routingOrder++, recordId));
}
// Recipient 2: Docusign Recipient #1
Id docusignRecipientId = (Id) caseRecord.get(FIELD_DOCUSIGN_RECIPIENT);
if (docusignRecipientId != null) {
recipients.add(buildRecipient(docusignRecipientId, ROLE_DOCUSIGN_RECIPIENT, routingOrder++, recordId));
}
if (recipients.isEmpty()) {
throw new IllegalArgumentException('No recipients found on the Client Case record. '
+ 'Please ensure Service Coordinator and Docusign Recipient #1 are populated.');
}
return recipients;
}
/**
* @description Builds a dfsle.Recipient from a Contact/User lookup ID
* @param recipientId The Contact or User record ID
* @param roleName The Docusign template role name
* @param routingOrder Signing order
* @param sourceRecordId The source Client_Case__c record ID
* @return dfsle.Recipient configured for the role
*/
private static dfsle.Recipient buildRecipient(Id recipientId, String roleName, Integer routingOrder, String sourceRecordId) {
// Determine if this is a Contact or User
String objectType = recipientId.getSObjectType().getDescribe().getName();
String recipientName;
String recipientEmail;
if (objectType == 'Contact') {
Contact c = [SELECT Id, Name, Email FROM Contact WHERE Id = :recipientId LIMIT 1];
recipientName = c.Name;
recipientEmail = c.Email;
} else if (objectType == 'User') {
User u = [SELECT Id, Name, Email FROM User WHERE Id = :recipientId LIMIT 1];
recipientName = u.Name;
recipientEmail = u.Email;
} else {
throw new IllegalArgumentException('Unsupported recipient type: ' + objectType
+ '. Expected Contact or User.');
}
if (String.isBlank(recipientEmail)) {
throw new IllegalArgumentException('No email found for ' + roleName + ' (' + recipientName + '). '
+ 'Please ensure the recipient has a valid email address.');
}
return dfsle.Recipient.fromSource(
recipientName,
recipientEmail,
null, // phone (optional)
roleName, // must match template role exactly
new dfsle.Entity(sourceRecordId) // source record for merge fields
);
}
private static void logResult(Integer templateCount, String envelopeId, String status, String errorMessage) {
System.debug(LoggingLevel.INFO, '=== Docusign Composite Envelope ===');
System.debug(LoggingLevel.INFO, 'Templates: ' + templateCount);