From 7df62e06caaa859096fcb17bb30be8e1b4eabd52 Mon Sep 17 00:00:00 2001 From: Paul Huliganga Date: Wed, 25 Feb 2026 10:05:36 -0500 Subject: [PATCH] refactor: extract Request and Result as standalone global classes - Created DocusignEnvelopeRequest.cls (separate global class for input) - Created DocusignEnvelopeResult.cls (separate global class for output) - Updated DocusignCompositeEnvelopeBuilder to use standalone classes - Updated DocusignEnvelopeRequestHandler to reference standalone classes - Updated all test classes to use new class references - Fixes Flow Builder visibility issues with nested inner classes - Better API design with clear input/output types - Easier to extend and reuse across other classes --- .../DocusignCompositeEnvelopeBuilder.cls | 70 ++----------------- .../DocusignCompositeEnvelopeBuilderTest.cls | 56 +++++++-------- .../classes/DocusignEnvelopeRequest.cls | 35 ++++++++++ .../DocusignEnvelopeRequest.cls-meta.xml | 5 ++ .../DocusignEnvelopeRequestHandler.cls | 4 +- .../DocusignEnvelopeRequestHandlerTest.cls | 18 ++--- .../classes/DocusignEnvelopeResult.cls | 25 +++++++ .../DocusignEnvelopeResult.cls-meta.xml | 5 ++ 8 files changed, 115 insertions(+), 103 deletions(-) create mode 100644 composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequest.cls create mode 100644 composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequest.cls-meta.xml create mode 100644 composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeResult.cls create mode 100644 composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeResult.cls-meta.xml 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 1fa2f3d..b322ead 100644 --- a/composite-envelope-builder/force-app/main/default/classes/DocusignCompositeEnvelopeBuilder.cls +++ b/composite-envelope-builder/force-app/main/default/classes/DocusignCompositeEnvelopeBuilder.cls @@ -15,16 +15,16 @@ global with sharing class DocusignCompositeEnvelopeBuilder { description='Combines multiple Docusign templates into a single envelope' category='Docusign' ) - public static List sendCompositeEnvelope(List requests) { - List results = new List(); + public static List sendCompositeEnvelope(List requests) { + List results = new List(); // Process first request (Flow only sends one) if (requests == null || requests.isEmpty()) { return buildErrorResult('No request provided'); } - Request req = requests[0]; - Result result = new Result(); + DocusignEnvelopeRequest req = requests[0]; + DocusignEnvelopeResult result = new DocusignEnvelopeResult(); try { // Validate request using handler @@ -104,67 +104,11 @@ global with sharing class DocusignCompositeEnvelopeBuilder { * @param errorMessage Error message * @return List containing single error result */ - private static List buildErrorResult(String errorMessage) { - Result result = new Result(); + private static List buildErrorResult(String errorMessage) { + DocusignEnvelopeResult result = new DocusignEnvelopeResult(); result.success = false; result.errorMessage = errorMessage; result.envelopeId = null; - return new List{ result }; - } - - /** - * @description Input parameters for invocable method (from Screen Flow) - */ - global class Request { - @InvocableVariable( - label='Template IDs' - description='List of Docusign template IDs to combine' - required=true - ) - public List templateIds; - - @InvocableVariable( - label='Salesforce Record ID' - description='ID of the Salesforce record to attach documents to' - required=true - ) - public String recordId; - - @InvocableVariable( - label='Language' - description='Language code (en or es)' - required=false - ) - public String language; - - @InvocableVariable( - label='Email Subject' - description='Subject line for envelope email' - required=false - ) - public String emailSubject; - } - - /** - * @description Output parameters for invocable method (to Screen Flow) - */ - global class Result { - @InvocableVariable( - label='Envelope ID' - description='Docusign envelope ID' - ) - public String envelopeId; - - @InvocableVariable( - label='Success' - description='True if envelope was created successfully' - ) - public Boolean success; - - @InvocableVariable( - label='Error Message' - description='Error message if envelope creation failed' - ) - public String errorMessage; + return new List{ result }; } } diff --git a/composite-envelope-builder/force-app/main/default/classes/DocusignCompositeEnvelopeBuilderTest.cls b/composite-envelope-builder/force-app/main/default/classes/DocusignCompositeEnvelopeBuilderTest.cls index 95b21c2..3f3e5df 100644 --- a/composite-envelope-builder/force-app/main/default/classes/DocusignCompositeEnvelopeBuilderTest.cls +++ b/composite-envelope-builder/force-app/main/default/classes/DocusignCompositeEnvelopeBuilderTest.cls @@ -51,7 +51,7 @@ private class DocusignCompositeEnvelopeBuilderTest { DocusignCredentials.setTestCredentials('test-account-id', 'callout:DocusignAPI', 'test-token'); - DocusignCompositeEnvelopeBuilder.Request req = new DocusignCompositeEnvelopeBuilder.Request(); + DocusignEnvelopeRequest req = new DocusignEnvelopeRequest(); req.templateIds = new List{'template-1', 'template-2', 'template-3'}; req.recordId = '001000000ABC123'; req.language = 'en'; @@ -59,8 +59,8 @@ private class DocusignCompositeEnvelopeBuilderTest { // Act Test.startTest(); - List results = - DocusignCompositeEnvelopeBuilder.sendCompositeEnvelope(new List{req}); + List results = + DocusignCompositeEnvelopeBuilder.sendCompositeEnvelope(new List{req}); Test.stopTest(); // Assert @@ -81,14 +81,14 @@ private class DocusignCompositeEnvelopeBuilderTest { DocusignCredentials.setTestCredentials('test-account-id', 'callout:DocusignAPI', 'test-token'); - DocusignCompositeEnvelopeBuilder.Request req = new DocusignCompositeEnvelopeBuilder.Request(); + DocusignEnvelopeRequest req = new DocusignEnvelopeRequest(); req.templateIds = new List{'template-1'}; req.recordId = '001000000ABC123'; // Act Test.startTest(); - List results = - DocusignCompositeEnvelopeBuilder.sendCompositeEnvelope(new List{req}); + List results = + DocusignCompositeEnvelopeBuilder.sendCompositeEnvelope(new List{req}); Test.stopTest(); // Assert @@ -111,14 +111,14 @@ private class DocusignCompositeEnvelopeBuilderTest { templateIds.add('template-' + i); } - DocusignCompositeEnvelopeBuilder.Request req = new DocusignCompositeEnvelopeBuilder.Request(); + DocusignEnvelopeRequest req = new DocusignEnvelopeRequest(); req.templateIds = templateIds; req.recordId = '001000000ABC123'; // Act Test.startTest(); - List results = - DocusignCompositeEnvelopeBuilder.sendCompositeEnvelope(new List{req}); + List results = + DocusignCompositeEnvelopeBuilder.sendCompositeEnvelope(new List{req}); Test.stopTest(); // Assert @@ -136,22 +136,20 @@ private class DocusignCompositeEnvelopeBuilderTest { DocusignCredentials.setTestCredentials('test-account-id', 'callout:DocusignAPI', 'test-token'); - DocusignCompositeEnvelopeBuilder.Request req = new DocusignCompositeEnvelopeBuilder.Request(); + DocusignEnvelopeRequest req = new DocusignEnvelopeRequest(); req.templateIds = new List{'template-1', 'template-2', 'template-1'}; // Duplicate req.recordId = '001000000ABC123'; // Act Test.startTest(); - List results = - DocusignCompositeEnvelopeBuilder.sendCompositeEnvelope(new List{req}); + List results = + DocusignCompositeEnvelopeBuilder.sendCompositeEnvelope(new List{req}); Test.stopTest(); // Assert System.assertEquals(true, results[0].success, 'Should handle duplicates'); } - // Custom fields test removed - not supported in InvocableVariable (Phase 2 enhancement) - /** * @description Test validation failure - no template IDs */ @@ -160,14 +158,14 @@ private class DocusignCompositeEnvelopeBuilderTest { // Arrange DocusignCredentials.setTestCredentials('test-account-id', 'callout:DocusignAPI', 'test-token'); - DocusignCompositeEnvelopeBuilder.Request req = new DocusignCompositeEnvelopeBuilder.Request(); + DocusignEnvelopeRequest req = new DocusignEnvelopeRequest(); req.templateIds = new List(); // Empty req.recordId = '001000000ABC123'; // Act Test.startTest(); - List results = - DocusignCompositeEnvelopeBuilder.sendCompositeEnvelope(new List{req}); + List results = + DocusignCompositeEnvelopeBuilder.sendCompositeEnvelope(new List{req}); Test.stopTest(); // Assert @@ -188,14 +186,14 @@ private class DocusignCompositeEnvelopeBuilderTest { templateIds.add('template-' + i); } - DocusignCompositeEnvelopeBuilder.Request req = new DocusignCompositeEnvelopeBuilder.Request(); + DocusignEnvelopeRequest req = new DocusignEnvelopeRequest(); req.templateIds = templateIds; // 15 templates (> max of 14) req.recordId = '001000000ABC123'; // Act Test.startTest(); - List results = - DocusignCompositeEnvelopeBuilder.sendCompositeEnvelope(new List{req}); + List results = + DocusignCompositeEnvelopeBuilder.sendCompositeEnvelope(new List{req}); Test.stopTest(); // Assert @@ -211,14 +209,14 @@ private class DocusignCompositeEnvelopeBuilderTest { // Arrange DocusignCredentials.setTestCredentials('test-account-id', 'callout:DocusignAPI', 'test-token'); - DocusignCompositeEnvelopeBuilder.Request req = new DocusignCompositeEnvelopeBuilder.Request(); + DocusignEnvelopeRequest req = new DocusignEnvelopeRequest(); req.templateIds = new List{'template-1'}; req.recordId = ''; // Blank // Act Test.startTest(); - List results = - DocusignCompositeEnvelopeBuilder.sendCompositeEnvelope(new List{req}); + List results = + DocusignCompositeEnvelopeBuilder.sendCompositeEnvelope(new List{req}); Test.stopTest(); // Assert @@ -237,14 +235,14 @@ private class DocusignCompositeEnvelopeBuilderTest { DocusignCredentials.setTestCredentials('test-account-id', 'callout:DocusignAPI', 'test-token'); - DocusignCompositeEnvelopeBuilder.Request req = new DocusignCompositeEnvelopeBuilder.Request(); + DocusignEnvelopeRequest req = new DocusignEnvelopeRequest(); req.templateIds = new List{'invalid-template'}; req.recordId = '001000000ABC123'; // Act Test.startTest(); - List results = - DocusignCompositeEnvelopeBuilder.sendCompositeEnvelope(new List{req}); + List results = + DocusignCompositeEnvelopeBuilder.sendCompositeEnvelope(new List{req}); Test.stopTest(); // Assert @@ -263,14 +261,14 @@ private class DocusignCompositeEnvelopeBuilderTest { DocusignCredentials.setTestCredentials('test-account-id', 'callout:DocusignAPI', 'invalid-token'); - DocusignCompositeEnvelopeBuilder.Request req = new DocusignCompositeEnvelopeBuilder.Request(); + DocusignEnvelopeRequest req = new DocusignEnvelopeRequest(); req.templateIds = new List{'template-1'}; req.recordId = '001000000ABC123'; // Act Test.startTest(); - List results = - DocusignCompositeEnvelopeBuilder.sendCompositeEnvelope(new List{req}); + List results = + DocusignCompositeEnvelopeBuilder.sendCompositeEnvelope(new List{req}); Test.stopTest(); // Assert diff --git a/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequest.cls b/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequest.cls new file mode 100644 index 0000000..9e83e96 --- /dev/null +++ b/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequest.cls @@ -0,0 +1,35 @@ +/** + * @description Input parameters for DocusignCompositeEnvelopeBuilder invocable method + * @author Paul Huliganga + * @date 2026-02-25 + */ +global class DocusignEnvelopeRequest { + + @InvocableVariable( + label='Template IDs' + description='List of Docusign template IDs to combine' + required=true + ) + global List templateIds; + + @InvocableVariable( + label='Salesforce Record ID' + description='ID of the Salesforce record to attach documents to' + required=true + ) + global String recordId; + + @InvocableVariable( + label='Language' + description='Language code (en or es)' + required=false + ) + global String language; + + @InvocableVariable( + label='Email Subject' + description='Subject line for envelope email' + required=false + ) + global String emailSubject; +} diff --git a/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequest.cls-meta.xml b/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequest.cls-meta.xml new file mode 100644 index 0000000..f5e18fd --- /dev/null +++ b/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequest.cls-meta.xml @@ -0,0 +1,5 @@ + + + 60.0 + Active + diff --git a/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequestHandler.cls b/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequestHandler.cls index 3e22e92..05004b3 100644 --- a/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequestHandler.cls +++ b/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequestHandler.cls @@ -10,7 +10,7 @@ global with sharing class DocusignEnvelopeRequestHandler { * @param req Request object to validate * @throws IllegalArgumentException if validation fails */ - public static void validateRequest(DocusignCompositeEnvelopeBuilder.Request req) { + public static void validateRequest(DocusignEnvelopeRequest req) { if (req.templateIds == null || req.templateIds.isEmpty()) { throw new IllegalArgumentException('At least one template ID is required'); } @@ -36,7 +36,7 @@ global with sharing class DocusignEnvelopeRequestHandler { * @param req Request object containing parameters * @return JSON string for Docusign API request */ - public static String buildEnvelopeJSON(DocusignCompositeEnvelopeBuilder.Request req) { + public static String buildEnvelopeJSON(DocusignEnvelopeRequest req) { // Remove duplicates and sort alphabetically List sortedTemplateIds = sortTemplatesAlphabetically( new Set(req.templateIds) diff --git a/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequestHandlerTest.cls b/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequestHandlerTest.cls index 80a9c61..97bb462 100644 --- a/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequestHandlerTest.cls +++ b/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeRequestHandlerTest.cls @@ -9,7 +9,7 @@ public class DocusignEnvelopeRequestHandlerTest { @isTest static void testValidateRequest_Success() { // Setup - DocusignCompositeEnvelopeBuilder.Request req = new DocusignCompositeEnvelopeBuilder.Request(); + DocusignEnvelopeRequest req = new DocusignEnvelopeRequest(); req.templateIds = new List{ 'template1', 'template2' }; req.recordId = '001xx000003DHf'; req.language = 'en'; @@ -27,7 +27,7 @@ public class DocusignEnvelopeRequestHandlerTest { @isTest static void testValidateRequest_NoTemplateIds() { // Setup - DocusignCompositeEnvelopeBuilder.Request req = new DocusignCompositeEnvelopeBuilder.Request(); + DocusignEnvelopeRequest req = new DocusignEnvelopeRequest(); req.templateIds = new List(); req.recordId = '001xx000003DHf'; @@ -45,7 +45,7 @@ public class DocusignEnvelopeRequestHandlerTest { @isTest static void testValidateRequest_TooManyTemplates() { // Setup - DocusignCompositeEnvelopeBuilder.Request req = new DocusignCompositeEnvelopeBuilder.Request(); + DocusignEnvelopeRequest req = new DocusignEnvelopeRequest(); req.templateIds = new List(); for (Integer i = 0; i < 15; i++) { req.templateIds.add('template' + i); @@ -66,7 +66,7 @@ public class DocusignEnvelopeRequestHandlerTest { @isTest static void testValidateRequest_NoRecordId() { // Setup - DocusignCompositeEnvelopeBuilder.Request req = new DocusignCompositeEnvelopeBuilder.Request(); + DocusignEnvelopeRequest req = new DocusignEnvelopeRequest(); req.templateIds = new List{ 'template1' }; req.recordId = ''; @@ -84,7 +84,7 @@ public class DocusignEnvelopeRequestHandlerTest { @isTest static void testValidateRequest_BlankTemplateId() { // Setup - DocusignCompositeEnvelopeBuilder.Request req = new DocusignCompositeEnvelopeBuilder.Request(); + DocusignEnvelopeRequest req = new DocusignEnvelopeRequest(); req.templateIds = new List{ 'template1', '', 'template3' }; req.recordId = '001xx000003DHf'; @@ -102,7 +102,7 @@ public class DocusignEnvelopeRequestHandlerTest { @isTest static void testBuildEnvelopeJSON_Success() { // Setup - DocusignCompositeEnvelopeBuilder.Request req = new DocusignCompositeEnvelopeBuilder.Request(); + DocusignEnvelopeRequest req = new DocusignEnvelopeRequest(); req.templateIds = new List{ 'template2', 'template1', 'template2' }; // duplicates and unsorted req.recordId = '001xx000003DHf'; req.language = 'es'; @@ -123,7 +123,7 @@ public class DocusignEnvelopeRequestHandlerTest { @isTest static void testBuildEnvelopeJSON_DefaultSubject() { // Setup - DocusignCompositeEnvelopeBuilder.Request req = new DocusignCompositeEnvelopeBuilder.Request(); + DocusignEnvelopeRequest req = new DocusignEnvelopeRequest(); req.templateIds = new List{ 'template1' }; req.recordId = '001xx000003DHf'; req.emailSubject = null; @@ -140,7 +140,7 @@ public class DocusignEnvelopeRequestHandlerTest { @isTest static void testBuildEnvelopeJSON_TemplatesAreSorted() { // Setup - DocusignCompositeEnvelopeBuilder.Request req = new DocusignCompositeEnvelopeBuilder.Request(); + DocusignEnvelopeRequest req = new DocusignEnvelopeRequest(); req.templateIds = new List{ 'template3', 'template1', 'template2' }; req.recordId = '001xx000003DHf'; @@ -159,7 +159,7 @@ public class DocusignEnvelopeRequestHandlerTest { @isTest static void testBuildEnvelopeJSON_DuplicatesRemoved() { // Setup - DocusignCompositeEnvelopeBuilder.Request req = new DocusignCompositeEnvelopeBuilder.Request(); + DocusignEnvelopeRequest req = new DocusignEnvelopeRequest(); req.templateIds = new List{ 'template1', 'template1', 'template2' }; req.recordId = '001xx000003DHf'; diff --git a/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeResult.cls b/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeResult.cls new file mode 100644 index 0000000..9cd5c53 --- /dev/null +++ b/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeResult.cls @@ -0,0 +1,25 @@ +/** + * @description Output parameters for DocusignCompositeEnvelopeBuilder invocable method + * @author Paul Huliganga + * @date 2026-02-25 + */ +global class DocusignEnvelopeResult { + + @InvocableVariable( + label='Envelope ID' + description='Docusign envelope ID' + ) + global String envelopeId; + + @InvocableVariable( + label='Success' + description='True if envelope was created successfully' + ) + global Boolean success; + + @InvocableVariable( + label='Error Message' + description='Error message if envelope creation failed' + ) + global String errorMessage; +} diff --git a/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeResult.cls-meta.xml b/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeResult.cls-meta.xml new file mode 100644 index 0000000..f5e18fd --- /dev/null +++ b/composite-envelope-builder/force-app/main/default/classes/DocusignEnvelopeResult.cls-meta.xml @@ -0,0 +1,5 @@ + + + 60.0 + Active +