salesforce-composite-envelo.../composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequestHand...

174 lines
6.2 KiB
OpenEdge ABL

/**
* @description Handles request validation and envelope JSON building for Docusign composite envelopes
* @author Paul Huliganga
* @date 2026-02-25
*/
global with sharing class DocusignEnvelopeRequestHandler {
/**
* @description Validates composite envelope request parameters
* @param req Request object to validate
* @throws IllegalArgumentException if validation fails
*/
public static void validateRequest(DocusignCompositeEnvelopeBuilder.Request req) {
if (req.templateIds == null || req.templateIds.isEmpty()) {
throw new IllegalArgumentException('At least one template ID is required');
}
if (req.templateIds.size() > 14) {
throw new IllegalArgumentException('Maximum 14 templates allowed per envelope');
}
if (String.isBlank(req.recordId)) {
throw new IllegalArgumentException('Salesforce record ID is required');
}
// Check for null template IDs
for (String templateId : req.templateIds) {
if (String.isBlank(templateId)) {
throw new IllegalArgumentException('Template ID cannot be blank');
}
}
}
/**
* @description Builds composite envelope JSON for Docusign API from request
* @param req Request object containing parameters
* @return JSON string for Docusign API request
*/
public static String buildEnvelopeJSON(DocusignCompositeEnvelopeBuilder.Request req) {
// Remove duplicates and sort alphabetically
List<String> sortedTemplateIds = sortTemplatesAlphabetically(
new Set<String>(req.templateIds)
);
// Build composite envelope JSON
return buildCompositeEnvelopeJSON(
sortedTemplateIds,
req.recordId,
req.language,
req.emailSubject,
null // customFields not supported in InvocableVariable (Phase 2 enhancement)
);
}
/**
* @description Removes duplicates and sorts template IDs alphabetically
* @param templateIdSet Set of template IDs
* @return Sorted list of unique template IDs
*/
private static List<String> sortTemplatesAlphabetically(Set<String> templateIdSet) {
List<String> sortedList = new List<String>(templateIdSet);
sortedList.sort();
return sortedList;
}
/**
* @description Builds composite envelope JSON for Docusign API
* @param templateIds List of template IDs to combine
* @param recordId Salesforce record ID for custom fields
* @param language Language code (en/es)
* @param emailSubject Email subject line
* @param customFields Map of custom field name/value pairs
* @return JSON string for Docusign API request
*/
private static String buildCompositeEnvelopeJSON(
List<String> templateIds,
String recordId,
String language,
String emailSubject,
Map<String, String> customFields
) {
// Build composite templates array
List<Object> compositeTemplates = new List<Object>();
Integer sequence = 1;
for (String templateId : templateIds) {
Map<String, Object> compositeTemplate = new Map<String, Object>{
'compositeTemplateId' => String.valueOf(sequence),
'serverTemplates' => new List<Object>{
new Map<String, Object>{
'sequence' => String.valueOf(sequence),
'templateId' => templateId
}
}
};
// Add custom fields if this is the first template
if (sequence == 1 && (String.isNotBlank(recordId) || customFields != null)) {
compositeTemplate.put('inlineTemplates', buildInlineTemplates(recordId, language, customFields));
}
compositeTemplates.add(compositeTemplate);
sequence++;
}
// Build envelope object
Map<String, Object> envelope = new Map<String, Object>{
'status' => 'sent',
'emailSubject' => String.isNotBlank(emailSubject)
? emailSubject
: 'Please review and sign these forms',
'compositeTemplates' => compositeTemplates
};
return JSON.serialize(envelope);
}
/**
* @description Builds inline templates for custom fields
* @param recordId Salesforce record ID
* @param language Language code
* @param customFields Additional custom fields
* @return List of inline template objects
*/
private static List<Object> buildInlineTemplates(
String recordId,
String language,
Map<String, String> customFields
) {
List<Object> textCustomFields = new List<Object>();
// Add Salesforce record ID
if (String.isNotBlank(recordId)) {
textCustomFields.add(new Map<String, Object>{
'name' => 'SalesforceRecordId',
'value' => recordId,
'show' => 'false',
'required' => 'false'
});
}
// Add language
if (String.isNotBlank(language)) {
textCustomFields.add(new Map<String, Object>{
'name' => 'Language',
'value' => language,
'show' => 'false',
'required' => 'false'
});
}
// Add additional custom fields
if (customFields != null && !customFields.isEmpty()) {
for (String fieldName : customFields.keySet()) {
textCustomFields.add(new Map<String, Object>{
'name' => fieldName,
'value' => customFields.get(fieldName),
'show' => 'false',
'required' => 'false'
});
}
}
return new List<Object>{
new Map<String, Object>{
'sequence' => '1',
'customFields' => new Map<String, Object>{
'textCustomFields' => textCustomFields
}
}
};
}
}