diff --git a/composite-envelope-builder/force-app/main/default/classes/DocusignCompositeEnvelopeBuilder.cls b/composite-envelope-builder/force-app/main/default/classes/DocusignCompositeEnvelopeBuilder.cls index 95d00d5..efb3f45 100644 --- a/composite-envelope-builder/force-app/main/default/classes/DocusignCompositeEnvelopeBuilder.cls +++ b/composite-envelope-builder/force-app/main/default/classes/DocusignCompositeEnvelopeBuilder.cls @@ -28,6 +28,17 @@ global with sharing class DocusignCompositeEnvelopeBuilder { // ============================================================ @TestVisible private static final String MULTI_COPY_TEMPLATE_NAME = 'Authorization to Release Information'; + + // ============================================================ + // SMS DELIVERY: Placeholder email used when the primary recipient + // (Docusign Recipient #1) has no email and SMS delivery is requested. + // Docusign requires an email on every recipient even when delivery + // is via SMS; this constant satisfies that requirement without + // routing any actual email. Update this value if your org uses a + // different placeholder address. + // ============================================================ + @TestVisible + private static final String SMS_FALLBACK_EMAIL = 'placeholder_email@docusign.com'; @InvocableMethod( label='Send Composite Docusign Envelope' @@ -188,7 +199,7 @@ global with sharing class DocusignCompositeEnvelopeBuilder { } // Resolve recipients from Client_Case__c lookup fields - List recipients = resolveRecipients(req.recordId); + List recipients = resolveRecipients(req.recordId, req.recipientSmsPhone); myEnvelope = myEnvelope.withRecipients(recipients); // Set envelope subject to combined display names (deduplicated, with copy counts). @@ -222,11 +233,25 @@ global with sharing class DocusignCompositeEnvelopeBuilder { String envelopeBody = bodyParts.isEmpty() ? '' : String.join(bodyParts, '\n\n'); myEnvelope = myEnvelope.withEmail(envelopeSubject, envelopeBody); - // Send the envelope - myEnvelope = dfsle.EnvelopeService.sendEnvelope(myEnvelope, true); - - // Success - result.envelopeId = String.valueOf(myEnvelope.docuSignId); + // Send the envelope. + // When a recipient SMS phone is supplied we bypass the dfsle Toolkit entirely + // because it cannot set additionalNotifications for SMS delivery. + // DocusignSmsEnvelopeService posts directly to the Docusign REST API instead. + if (String.isNotBlank(req.recipientSmsPhone)) { + String envelopeId = DocusignSmsEnvelopeService.sendEnvelope( + req.recordId, + sortedIds, + docNames, + displayNames, + envelopeSubject, + envelopeBody, + req.recipientSmsPhone + ); + result.envelopeId = envelopeId; + } else { + myEnvelope = dfsle.EnvelopeService.sendEnvelope(myEnvelope, true); + result.envelopeId = String.valueOf(myEnvelope.docuSignId); + } result.success = true; result.errorMessage = null; @@ -256,9 +281,13 @@ global with sharing class DocusignCompositeEnvelopeBuilder { * @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 + * @param smsPhone Optional SMS phone for the primary recipient when they have no email. + * When non-blank, buildRecipient will substitute SMS_FALLBACK_EMAIL + * for the Docusign Recipient #1 role instead of throwing an error. + * (Only relevant for the dfsle path — the SMS service resolves its own recipients.) * @return List of dfsle.Recipient objects with role mappings */ - private static List resolveRecipients(String recordId) { + private static List resolveRecipients(String recordId, String smsPhone) { // 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, ' @@ -274,13 +303,13 @@ global with sharing class DocusignCompositeEnvelopeBuilder { // Recipient 1: Service Coordinator Id serviceCoordinatorId = (Id) caseRecord.get(FIELD_SERVICE_COORDINATOR); if (serviceCoordinatorId != null) { - recipients.add(buildRecipient(serviceCoordinatorId, ROLE_SERVICE_COORDINATOR, routingOrder++, recordId)); + recipients.add(buildRecipient(serviceCoordinatorId, ROLE_SERVICE_COORDINATOR, routingOrder++, recordId, null)); } // 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)); + recipients.add(buildRecipient(docusignRecipientId, ROLE_DOCUSIGN_RECIPIENT, routingOrder++, recordId, smsPhone)); } if (recipients.isEmpty()) { @@ -297,9 +326,14 @@ global with sharing class DocusignCompositeEnvelopeBuilder { * @param roleName The Docusign template role name * @param routingOrder Signing order * @param sourceRecordId The source Client_Case__c record ID + * @param smsPhone Optional SMS phone number for the Docusign Recipient #1 role. + * When non-blank and the recipient has no email, SMS_FALLBACK_EMAIL + * is substituted so the dfsle Toolkit call can proceed. + * (The actual SMS delivery notification is handled separately by + * DocusignSmsEnvelopeService — this path is a safety fallback only.) * @return dfsle.Recipient configured for the role */ - private static dfsle.Recipient buildRecipient(Id recipientId, String roleName, Integer routingOrder, String sourceRecordId) { + private static dfsle.Recipient buildRecipient(Id recipientId, String roleName, Integer routingOrder, String sourceRecordId, String smsPhone) { // Determine if this is a Contact or User String objectType = recipientId.getSObjectType().getDescribe().getName(); @@ -320,8 +354,14 @@ global with sharing class DocusignCompositeEnvelopeBuilder { } if (String.isBlank(recipientEmail)) { - throw new IllegalArgumentException('No email found for ' + roleName + ' (' + recipientName + '). ' - + 'Please ensure the recipient has a valid email address.'); + if (roleName == ROLE_DOCUSIGN_RECIPIENT && String.isNotBlank(smsPhone)) { + // Recipient has no email but SMS delivery is requested — substitute + // the placeholder email so the dfsle Toolkit call does not throw. + recipientEmail = SMS_FALLBACK_EMAIL; + } else { + throw new IllegalArgumentException('No email found for ' + roleName + ' (' + recipientName + '). ' + + 'Please ensure the recipient has a valid email address.'); + } } return dfsle.Recipient.fromSource( diff --git a/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequest.cls b/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequest.cls index 84c074d..9143452 100644 --- a/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequest.cls +++ b/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequest.cls @@ -39,4 +39,11 @@ global class DocusignEnvelopeRequest { required=false ) global Integer authReleaseFormCopies; + + @InvocableVariable( + label='Recipient SMS Phone' + description='Mobile phone number for SMS delivery when the primary recipient (Docusign Recipient #1) has no email address. E.164 format preferred (e.g. +15551234567). When provided, the envelope is sent via direct Docusign REST API instead of the dfsle Toolkit so that additionalNotifications/SMS delivery can be set.' + required=false + ) + global String recipientSmsPhone; } diff --git a/composite-envelope-builder/force-app/main/default/classes/DocusignSmsEnvelopeService.cls b/composite-envelope-builder/force-app/main/default/classes/DocusignSmsEnvelopeService.cls new file mode 100644 index 0000000..816ee1a --- /dev/null +++ b/composite-envelope-builder/force-app/main/default/classes/DocusignSmsEnvelopeService.cls @@ -0,0 +1,414 @@ +/** + * @description Sends a Docusign composite envelope via direct REST API call when the + * primary recipient (Docusign Recipient #1) does not have an email address + * and requires SMS delivery instead. + * + * The dfsle Apex Toolkit does not support the Docusign + * additionalNotifications/secondaryDeliveryMethod property needed for + * SMS-only recipients, so this service bypasses the toolkit and calls + * the Docusign REST API directly. + * + * Prerequisites: + * - Named Credential "DocusignAPI" must be configured in the org. + * - Docusign account must have SMS delivery enabled. + * - Docusign_Configuration__c custom setting must have Account_Id__c populated. + * + * @author Paul Huliganga + * @date 2026-02-25 + */ +global with sharing class DocusignSmsEnvelopeService { + + // Named Credential for Docusign REST API callouts + @TestVisible + private static final String NAMED_CREDENTIAL = 'callout:DocusignAPI'; + + // Endpoint path template — {0} is replaced with the accountId + @TestVisible + private static final String ENVELOPES_PATH = '/accounts/{0}/envelopes'; + + // Dummy email used for SMS-only recipients. Docusign requires an email address + // on every recipient even when delivery is via SMS. This placeholder satisfies + // that requirement without routing any actual email. + @TestVisible + private static final String SMS_PLACEHOLDER_EMAIL = 'placeholder_email@docusign.com'; + + // Country code assumed when the caller supplies a bare 10-digit US number. + // The flow enforces E.164 format (e.g. +15551234567) so this is a safety fallback. + private static final String DEFAULT_COUNTRY_CODE = '1'; + + /** + * @description Builds and sends a composite Docusign envelope with SMS delivery for + * the primary recipient. Mirrors the logic in DocusignCompositeEnvelopeBuilder + * but constructs the JSON payload manually so that additionalNotifications + * can be included on the recipient object. + * + * @param recordId The Client_Case__c record ID (used to look up recipients) + * @param sortedIds Template IDs in sorted order (may contain duplicates for multi-copy) + * @param docNames Document labels in same order as sortedIds + * @param displayNames Deduplicated display labels for email subject / body + * @param envelopeSubject Email subject line (already formatted and truncated) + * @param envelopeBody Email body text (already formatted and deduplicated) + * @param smsPhone Mobile phone number for SMS delivery (E.164 preferred, e.g. +15551234567) + * @return Docusign envelope ID string on success + * @throws IllegalArgumentException when recipients or configuration data are missing + * @throws CalloutException on HTTP errors + */ + global static String sendEnvelope( + String recordId, + List sortedIds, + List docNames, + List displayNames, + String envelopeSubject, + String envelopeBody, + String smsPhone + ) { + // ─── Fetch Docusign account ID from custom setting ─────────────────────────── + Docusign_Configuration__c config = Docusign_Configuration__c.getInstance(); + if (config == null || String.isBlank(config.Account_Id__c)) { + throw new IllegalArgumentException( + 'Docusign_Configuration__c is not configured. ' + + 'Please set Account_Id__c in the Docusign Configuration custom setting.' + ); + } + String accountId = config.Account_Id__c; + + // ─── Resolve recipients from Client_Case__c ─────────────────────────────────── + RecipientInfo serviceCoordinator = null; + RecipientInfo docusignRecipient = null; + + String query = 'SELECT Id, Service_Coordinator__c, Docusign_Recipient_1__c ' + + 'FROM Client_Case__c WHERE Id = :recordId LIMIT 1'; + Client_Case__c caseRecord = Database.query(query); + + Id scId = (Id) caseRecord.get('Service_Coordinator__c'); + Id drId = (Id) caseRecord.get('Docusign_Recipient_1__c'); + + if (scId != null) { + serviceCoordinator = resolveRecipient(scId, 'Service Coordinator', 1, null, false); + } + if (drId != null) { + // SMS phone provided — substitute placeholder email for the Docusign Recipient + docusignRecipient = resolveRecipient(drId, 'Docusign Recipient #1', 2, smsPhone, true); + } + + if (serviceCoordinator == null && docusignRecipient == null) { + throw new IllegalArgumentException( + 'No recipients found on the Client Case record. ' + + 'Please ensure Service Coordinator and Docusign Recipient #1 are populated.' + ); + } + + // ─── Build JSON body ───────────────────────────────────────────────────────── + String jsonBody = buildEnvelopeJson( + sortedIds, + docNames, + envelopeSubject, + envelopeBody, + serviceCoordinator, + docusignRecipient, + recordId + ); + + // ─── Call the Docusign REST API ─────────────────────────────────────────────── + String endpoint = NAMED_CREDENTIAL + + String.format(ENVELOPES_PATH, new List{ accountId }); + + HttpRequest httpReq = new HttpRequest(); + httpReq.setEndpoint(endpoint); + httpReq.setMethod('POST'); + httpReq.setHeader('Content-Type', 'application/json'); + httpReq.setHeader('Accept', 'application/json'); + httpReq.setBody(jsonBody); + + Http http = new Http(); + HttpResponse httpResp = http.send(httpReq); + + Integer statusCode = httpResp.getStatusCode(); + String responseBody = httpResp.getBody(); + + if (statusCode == 200 || statusCode == 201) { + // Parse envelopeId from response + Map responseMap = (Map) JSON.deserializeUntyped(responseBody); + Object envelopeIdObj = responseMap.get('envelopeId'); + if (envelopeIdObj == null) { + throw new CalloutException( + 'Docusign API returned success but no envelopeId in response: ' + responseBody + ); + } + return String.valueOf(envelopeIdObj); + } else { + // Try to extract a meaningful error message from the response JSON + String errorDetail = parseDocusignError(responseBody); + throw new CalloutException( + 'Docusign API returned HTTP ' + statusCode + ': ' + errorDetail + ); + } + } + + // ───────────────────────────────────────────────────────────────────────────────── + // PRIVATE HELPERS + // ───────────────────────────────────────────────────────────────────────────────── + + /** + * @description Resolves a recipient's name and email from a Contact or User record. + * When applySmsPlaceholder is true and the record has no email, + * the SMS_PLACEHOLDER_EMAIL constant is used instead. + */ + private static RecipientInfo resolveRecipient( + Id recipientId, + String roleName, + Integer routingOrder, + String smsPhone, + Boolean applySmsPlaceholder + ) { + String objectType = recipientId.getSObjectType().getDescribe().getName(); + String name; + String email; + + if (objectType == 'Contact') { + Contact c = [SELECT Id, Name, Email FROM Contact WHERE Id = :recipientId LIMIT 1]; + name = c.Name; + email = c.Email; + } else if (objectType == 'User') { + User u = [SELECT Id, Name, Email FROM User WHERE Id = :recipientId LIMIT 1]; + name = u.Name; + email = u.Email; + } else { + throw new IllegalArgumentException( + 'Unsupported recipient type: ' + objectType + '. Expected Contact or User.' + ); + } + + if (String.isBlank(email)) { + if (applySmsPlaceholder) { + email = SMS_PLACEHOLDER_EMAIL; + } else { + throw new IllegalArgumentException( + 'No email found for ' + roleName + ' (' + name + '). ' + + 'Please ensure the recipient has a valid email address.' + ); + } + } + + RecipientInfo info = new RecipientInfo(); + info.name = name; + info.email = email; + info.roleName = roleName; + info.routingOrder = routingOrder; + info.smsPhone = applySmsPlaceholder ? smsPhone : null; + return info; + } + + /** + * @description Constructs the full envelope JSON payload for the Docusign REST API. + * Uses compositeTemplates so that all selected templates are merged into + * a single envelope, matching what the dfsle Toolkit does internally. + * + * Docusign compositeTemplates reference: + * https://developers.docusign.com/docs/esign-rest-api/reference/envelopes/envelopes/create/ + */ + @TestVisible + private static String buildEnvelopeJson( + List sortedIds, + List docNames, + String envelopeSubject, + String envelopeBody, + RecipientInfo serviceCoordinator, + RecipientInfo docusignRecipient, + String sourceRecordId + ) { + // Build the recipients object (shared across all compositeTemplates) + // Each recipient gets a unique recipientId (sequential string integer). + List signers = new List(); + Integer recipientIdCounter = 1; + + if (serviceCoordinator != null) { + signers.add(buildSignerMap(serviceCoordinator, String.valueOf(recipientIdCounter++))); + } + if (docusignRecipient != null) { + signers.add(buildSignerMap(docusignRecipient, String.valueOf(recipientIdCounter++))); + } + + Map recipientsMap = new Map{ + 'signers' => signers + }; + + // Build compositeTemplates array — one entry per document (template ID + label) + List compositeTemplates = new List(); + for (Integer i = 0; i < sortedIds.size(); i++) { + String templateId = sortedIds[i]; + String docLabel = docNames[i]; + + Map serverTemplate = new Map{ + 'sequence' => '1', + 'templateId' => templateId + }; + + // Inline template overrides — set the document label and wire up role assignments + List inlineRecipientSigners = new List(); + Integer irCounter = 1; + if (serviceCoordinator != null) { + inlineRecipientSigners.add(new Map{ + 'recipientId' => String.valueOf(irCounter++), + 'roleName' => serviceCoordinator.roleName, + 'name' => serviceCoordinator.name, + 'email' => serviceCoordinator.email, + 'routingOrder' => String.valueOf(serviceCoordinator.routingOrder) + }); + } + if (docusignRecipient != null) { + Map drSigner = new Map{ + 'recipientId' => String.valueOf(irCounter++), + 'roleName' => docusignRecipient.roleName, + 'name' => docusignRecipient.name, + 'email' => docusignRecipient.email, + 'routingOrder' => String.valueOf(docusignRecipient.routingOrder) + }; + // Add SMS additionalNotifications for this recipient + if (String.isNotBlank(docusignRecipient.smsPhone)) { + String[] phoneParts = parsePhone(docusignRecipient.smsPhone); + drSigner.put('additionalNotifications', new List{ + new Map{ + 'secondaryDeliveryMethod' => 'SMS', + 'phoneNumber' => new Map{ + 'countryCode' => phoneParts[0], + 'number' => phoneParts[1] + } + } + }); + } + inlineRecipientSigners.add(drSigner); + } + + Map inlineTemplate = new Map{ + 'sequence' => '2', + 'recipients' => new Map{ + 'signers' => inlineRecipientSigners + }, + 'document' => new Map{ + 'name' => docLabel, + 'documentId' => String.valueOf(i + 1), + 'transformPdfFields' => 'true' + } + }; + + compositeTemplates.add(new Map{ + 'serverTemplates' => new List{ serverTemplate }, + 'inlineTemplates' => new List{ inlineTemplate }, + 'recipients' => recipientsMap + }); + } + + Map envelopeDefinition = new Map{ + 'status' => 'sent', + 'emailSubject' => envelopeSubject, + 'emailBlurb' => envelopeBody, + 'compositeTemplates' => compositeTemplates + }; + + return JSON.serialize(envelopeDefinition); + } + + /** + * @description Builds the signer map for a recipient in the envelope-level recipients object. + * Adds additionalNotifications for SMS recipients. + */ + private static Map buildSignerMap(RecipientInfo info, String recipientId) { + Map signer = new Map{ + 'recipientId' => recipientId, + 'name' => info.name, + 'email' => info.email, + 'roleName' => info.roleName, + 'routingOrder' => String.valueOf(info.routingOrder) + }; + + if (String.isNotBlank(info.smsPhone)) { + String[] phoneParts = parsePhone(info.smsPhone); + signer.put('additionalNotifications', new List{ + new Map{ + 'secondaryDeliveryMethod' => 'SMS', + 'phoneNumber' => new Map{ + 'countryCode' => phoneParts[0], + 'number' => phoneParts[1] + } + } + }); + } + + return signer; + } + + /** + * @description Parses a phone number into [countryCode, nationalNumber]. + * Accepts E.164 format (+15551234567) or a bare 10-digit number. + * Returns [DEFAULT_COUNTRY_CODE, strippedNumber] for bare numbers. + * + * @param phone Raw phone string from the flow input + * @return String array: index 0 = country code, index 1 = national number (digits only) + */ + @TestVisible + private static String[] parsePhone(String phone) { + if (String.isBlank(phone)) { + return new String[]{ DEFAULT_COUNTRY_CODE, '' }; + } + + String stripped = phone.replaceAll('[^\\d+]', ''); // keep digits and leading + + + if (stripped.startsWith('+')) { + // E.164: determine country code length heuristically + // We only support 1-digit (+1) and 2-digit (+XX) country codes for now + String digits = stripped.substring(1); // remove leading + + if (digits.length() == 11 && digits.startsWith('1')) { + // +1XXXXXXXXXX (North American Numbering Plan) + return new String[]{ '1', digits.substring(1) }; + } else if (digits.length() == 12) { + // +XXXXXXXXXXXX (2-digit country code + 10 digit number) + return new String[]{ digits.left(2), digits.substring(2) }; + } else { + // Fall back: treat first digit(s) as country code not supported; use full digits + return new String[]{ DEFAULT_COUNTRY_CODE, digits }; + } + } + + // Bare digits — assume DEFAULT_COUNTRY_CODE + return new String[]{ DEFAULT_COUNTRY_CODE, stripped }; + } + + /** + * @description Attempts to extract a human-readable error message from a Docusign + * REST API error response JSON. + * @param responseBody Raw HTTP response body + * @return Error string with errorCode and message if available, otherwise raw body + */ + private static String parseDocusignError(String responseBody) { + if (String.isBlank(responseBody)) { + return '(no response body)'; + } + try { + Map errorMap = (Map) JSON.deserializeUntyped(responseBody); + String errorCode = errorMap.containsKey('errorCode') ? String.valueOf(errorMap.get('errorCode')) : null; + String message = errorMap.containsKey('message') ? String.valueOf(errorMap.get('message')) : null; + if (String.isNotBlank(errorCode) || String.isNotBlank(message)) { + return (errorCode != null ? '[' + errorCode + '] ' : '') + (message != null ? message : ''); + } + } catch (Exception ex) { + // Non-JSON response — return raw body below + } + return responseBody.left(500); // cap at 500 chars to avoid log spam + } + + // ───────────────────────────────────────────────────────────────────────────────── + // INNER CLASSES + // ───────────────────────────────────────────────────────────────────────────────── + + /** + * @description Lightweight holder for resolved recipient data. + */ + private class RecipientInfo { + String name; + String email; + String roleName; + Integer routingOrder; + String smsPhone; // null for email recipients; phone string for SMS recipients + } +} diff --git a/composite-envelope-builder/force-app/main/default/classes/DocusignSmsEnvelopeService.cls-meta.xml b/composite-envelope-builder/force-app/main/default/classes/DocusignSmsEnvelopeService.cls-meta.xml new file mode 100644 index 0000000..f5e18fd --- /dev/null +++ b/composite-envelope-builder/force-app/main/default/classes/DocusignSmsEnvelopeService.cls-meta.xml @@ -0,0 +1,5 @@ + + + 60.0 + Active + diff --git a/composite-envelope-builder/force-app/main/default/flows/Docusign_Envelope_Templates_V3.flow-meta.xml b/composite-envelope-builder/force-app/main/default/flows/Docusign_Envelope_Templates_V3.flow-meta.xml index 7df9fdc..ac246f0 100644 --- a/composite-envelope-builder/force-app/main/default/flows/Docusign_Envelope_Templates_V3.flow-meta.xml +++ b/composite-envelope-builder/force-app/main/default/flows/Docusign_Envelope_Templates_V3.flow-meta.xml @@ -35,6 +35,12 @@ authReleaseFormCopies + + recipientSmsPhone + + recipientSmsPhone + + DocusignCompositeEnvelopeBuilder 0 @@ -179,7 +185,7 @@ Is_Language_Selected 611 - 242 + 458 Language_Not_Added_Screen @@ -225,6 +231,109 @@ + + Get_Recipient_Contact + + 611 + 242 + true + + Is_Recipient_Email_Blank + + and + + Id + EqualTo + + Get_Records.Docusign_Recipient_1__c + + + true + Contact + Id + Email + true + + + Is_Recipient_Email_Blank + + 611 + 350 + + Is_Language_Selected + + Has Email - Continue + + Recipient_Has_No_Email + or + + Get_Recipient_Contact.Email + IsNull + + true + + + + Get_Recipient_Contact.Email + EqualTo + + + + + + SMS_Required_Screen + + + + + + SMS_Required_Screen + + 842 + 458 + false + true + false + + Is_Language_Selected + + + SmsRequiredNotice + <p>⚠️ The primary recipient <strong>({!Get_Records.Docusign_Recipient_1__c})</strong> does not have an email address on file.</p><p><br></p><p>The DocuSign envelope will be delivered via <strong>SMS text message</strong> instead. Please enter the recipient's mobile phone number below.</p><p><br></p><p>Include the country code in E.164 format, e.g. <strong>+15551234567</strong> for a US number.</p> + DisplayText + + + top + + + 12 + + + + + recipientSmsPhone_Input + String + Mobile Phone Number + InputField + Enter the recipient's mobile phone number in E.164 format (e.g. +15551234567). The country code and + prefix are required for international numbers. + true + + recipientSmsPhone + value + + + + top + + + 6 + + + + Next + true + true + Default Docusign Envelope Templates V3 {!$Flow.CurrentDateTime} @@ -315,7 +424,7 @@ 134 false - Is_Language_Selected + Get_Recipient_Contact and @@ -329,6 +438,7 @@ Client_Case__c Id Docusign_Envelope_Language__c + Docusign_Recipient_1__c true @@ -636,6 +746,13 @@ false + + recipientSmsPhone + String + false + false + false + AuthCopies_1 1 copy