/** * @description Combines multiple Docusign templates into a single composite envelope * using the dfsle Apex Toolkit (Docusign for Salesforce managed package) * @author Paul Huliganga * @date 2026-02-25 */ global with sharing class DocusignCompositeEnvelopeBuilder { @InvocableMethod( label='Send Composite Docusign Envelope' description='Combines multiple Docusign templates into a single envelope using dfsle Apex Toolkit' category='Docusign' ) public static List sendCompositeEnvelope(List requests) { List results = new List(); if (requests == null || requests.isEmpty()) { return buildErrorResult('No request provided'); } DocusignEnvelopeRequest req = requests[0]; DocusignEnvelopeResult result = new DocusignEnvelopeResult(); try { // Validate request DocusignEnvelopeRequestHandler.validateRequest(req); // Create empty envelope linked to the source Salesforce record dfsle.Envelope myEnvelope = dfsle.EnvelopeService.getEmptyEnvelope( new dfsle.Entity(req.recordId) ); // Build document list from templates (deduplicated and sorted) List sortedTemplateIds = new List(new Set(req.templateIds)); sortedTemplateIds.sort(); List documents = new List(); for (String templateId : sortedTemplateIds) { documents.add( dfsle.Document.fromTemplate( dfsle.UUID.parse(templateId), 'Template ' + templateId.left(8) ) ); } // Add all templates as documents to the envelope myEnvelope = myEnvelope.withDocuments(documents); // Set email subject if provided if (String.isNotBlank(req.emailSubject)) { myEnvelope = myEnvelope.withEmail(req.emailSubject, ''); } // Send the envelope (true = send immediately) myEnvelope = dfsle.EnvelopeService.sendEnvelope(myEnvelope, true); // Success result.envelopeId = String.valueOf(myEnvelope.docuSignId); result.success = true; result.errorMessage = null; logResult(sortedTemplateIds.size(), result.envelopeId, 'Success', null); } catch (Exception e) { result.success = false; result.errorMessage = e.getMessage(); result.envelopeId = null; logResult( req.templateIds != null ? req.templateIds.size() : 0, null, 'Error', e.getMessage() + '\n' + e.getStackTraceString() ); if (e instanceof System.LimitException) { throw e; } } results.add(result); return results; } 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); System.debug(LoggingLevel.INFO, 'Envelope ID: ' + envelopeId); System.debug(LoggingLevel.INFO, 'Status: ' + status); if (String.isNotBlank(errorMessage)) { System.debug(LoggingLevel.ERROR, 'Error: ' + errorMessage); } } private static List buildErrorResult(String errorMessage) { DocusignEnvelopeResult result = new DocusignEnvelopeResult(); result.success = false; result.errorMessage = errorMessage; result.envelopeId = null; return new List{ result }; } }