diff --git a/composite-envelope-builder/force-app/main/default/classes/DocusignCompositeEnvelopeBuilder.cls.backup b/composite-envelope-builder/force-app/main/default/classes/DocusignCompositeEnvelopeBuilder.cls.backup deleted file mode 100644 index c5c26a5..0000000 --- a/composite-envelope-builder/force-app/main/default/classes/DocusignCompositeEnvelopeBuilder.cls.backup +++ /dev/null @@ -1,251 +0,0 @@ -/** - * @description Combines multiple Docusign templates into a single composite envelope - * 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' - 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 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(); - - // Query template names for document labels (shows in Docusign Status) - Map templateNames = new Map(); - for (dfsle__EnvelopeConfiguration__c config : [ - SELECT dfsle__DocuSignId__c, Name - FROM dfsle__EnvelopeConfiguration__c - WHERE dfsle__DocuSignId__c IN :sortedTemplateIds - ]) { - templateNames.put(config.dfsle__DocuSignId__c, config.Name); - } - - List documents = new List(); - List docNames = new List(); - for (String templateId : sortedTemplateIds) { - String label = templateNames.containsKey(templateId) - ? stripLanguageSuffix(templateNames.get(templateId)) - : templateId; - documents.add( - dfsle.Document.fromTemplate( - dfsle.UUID.parse(templateId), - label - ) - ); - docNames.add(label); - } - myEnvelope = myEnvelope.withDocuments(documents); - - // Set combined template names as the envelope document name - // (shows in Docusign Status "Document Name" column) - String combinedName = String.join(docNames, ', '); - if (combinedName.length() > 255) { - combinedName = combinedName.left(252) + '...'; - } - // Use combined name as the first document label so it appears in Status - if (!documents.isEmpty()) { - documents[0] = dfsle.Document.fromTemplate( - dfsle.UUID.parse(sortedTemplateIds[0]), - combinedName - ); - myEnvelope = myEnvelope.withDocuments(documents); - } - - // Resolve recipients from Client_Case__c lookup fields - List 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 - 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 (' + String.join(docNames, ', ') + ')', 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; - } - - /** - * @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 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 recipients = new List(); - 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); - System.debug(LoggingLevel.INFO, 'Envelope ID: ' + envelopeId); - System.debug(LoggingLevel.INFO, 'Status: ' + status); - if (String.isNotBlank(errorMessage)) { - System.debug(LoggingLevel.ERROR, 'Error: ' + errorMessage); - } - } - - /** - * @description Strips language suffixes like " - English" or " - Spanish" from template names - * @param name Template name - * @return Cleaned template name - */ - @TestVisible - private static String stripLanguageSuffix(String name) { - if (String.isBlank(name)) return name; - // Remove common language suffixes (case-insensitive) - String cleaned = name; - for (String suffix : new List{ - ' - English', ' - Spanish', ' - French', - ' - Anglais', ' - Espagnol', ' - Français' - }) { - if (cleaned.endsWithIgnoreCase(suffix)) { - cleaned = cleaned.left(cleaned.length() - suffix.length()); - break; - } - } - return cleaned.trim(); - } - - private static List buildErrorResult(String errorMessage) { - DocusignEnvelopeResult result = new DocusignEnvelopeResult(); - result.success = false; - result.errorMessage = errorMessage; - result.envelopeId = null; - return new List{ result }; - } -}