public class CLMDocGenCallout { // S1 demo environment private static final String CLM_ACCOUNT_ID_S1 = '2371cf36-eb8a-43fe-9f28-b5bbe7644397'; private static final String CLM_BASE_S1 = 'callout:CLMNamedCred/v2/' + CLM_ACCOUNT_ID_S1; // UAT demo environment private static final String CLM_ACCOUNT_ID_UAT = 'bccae332-c7db-4892-ab85-257df0f70fea'; private static final String CLM_BASE_UAT = 'callout:CLMuatNamedCreds/v2/' + CLM_ACCOUNT_ID_UAT; private static final Integer HTTP_TIMEOUT = 30000; /** Resolve the correct CLM base URL. env: 'UAT' or 'S1'. */ private static String clmBase(String env) { return env == 'S1' ? CLM_BASE_S1 : CLM_BASE_UAT; } /** Defaults to UAT environment. */ public static CLMDocGenResponse generateDocument( String caseId, String templateDocHref, String destinationFolderHref, String destinationDocName ) { return generateDocument(caseId, templateDocHref, destinationFolderHref, destinationDocName, 'UAT'); } /** * Generate a merged document via CLM documentxmlmergetasks (no user interaction). * @param caseId Appraiser_Case__c record Id * @param templateDocHref Full CLM Href URL of the template .docx document * @param destinationFolderHref Full CLM Href URL of the destination folder * @param destinationDocName Filename for the generated document, e.g. "Review_AC-00001.docx" * @param env 'UAT' (apiuatna11.springcm.com) or 'S1' (api.s1.us.clm.demo.docusign.net) */ public static CLMDocGenResponse generateDocument( String caseId, String templateDocHref, String destinationFolderHref, String destinationDocName, String env ) { Map casePayload = AppraiserCasePayloadBuilder.buildPayload(caseId); Map requestBody = new Map{ 'TemplateDocument' => new Map{ 'Href' => templateDocHref }, 'DataXML' => buildDataXml(casePayload), 'DestinationDocumentName' => destinationDocName, 'DestinationFolder' => new Map{ 'Href' => destinationFolderHref } }; HttpRequest req = new HttpRequest(); req.setEndpoint(clmBase(env) + '/documentxmlmergetasks'); req.setMethod('POST'); req.setHeader('Content-Type', 'application/json'); req.setTimeout(HTTP_TIMEOUT); req.setBody(JSON.serialize(requestBody)); try { Http http = new Http(); HttpResponse res = http.send(req); return parseTaskResponse(res); } catch (Exception ex) { return new CLMDocGenResponse(false, 'HTTP Callout Error: ' + ex.getMessage(), null, null); } } /** Poll the status of a submitted merge task by its GUID. */ /** Poll the status of a submitted merge task by its GUID (defaults to UAT). */ public static CLMDocGenResponse getTaskStatus(String taskId) { return getTaskStatus(taskId, 'UAT'); } public static CLMDocGenResponse getTaskStatus(String taskId, String env) { HttpRequest req = new HttpRequest(); req.setEndpoint(clmBase(env) + '/documentxmlmergetasks/' + taskId); req.setMethod('GET'); req.setTimeout(HTTP_TIMEOUT); try { Http http = new Http(); HttpResponse res = http.send(req); return parseTaskResponse(res); } catch (Exception ex) { return new CLMDocGenResponse(false, 'HTTP Callout Error: ' + ex.getMessage(), null, null); } } /** Probe any CLM resource path for debugging. env: 'UAT' or 'S1'. */ public static String probe(String resource) { return probe(resource, 'UAT'); } public static String probe(String resource, String env) { HttpRequest req = new HttpRequest(); req.setEndpoint(clmBase(env) + '/' + resource); req.setMethod('GET'); req.setTimeout(HTTP_TIMEOUT); HttpResponse res = new Http().send(req); return 'HTTP ' + res.getStatusCode() + ': ' + res.getBody(); } /** * Build the DataXML string from the case payload. * Flat fields become direct child elements of . * DeficiencyList items expand into numbered elements: * Deficiency_1_Number, Deficiency_1_Description, Deficiency_1_Resolution, etc. */ private static String buildDataXml(Map payload) { String xml = ''; for (String key : payload.keySet()) { if (key == 'DeficiencyList') continue; xml += '<' + key + '>' + escapeXml(String.valueOf(payload.get(key))) + ''; } List deficiencies = (List) payload.get('DeficiencyList'); if (deficiencies != null) { for (Integer i = 0; i < deficiencies.size(); i++) { Map d = (Map) deficiencies[i]; String p = 'Deficiency_' + (i + 1) + '_'; xml += '<' + p + 'Number>' + escapeXml(String.valueOf(d.get('deficiencyNumber'))) + ''; xml += '<' + p + 'Description>' + escapeXml(String.valueOf(d.get('description'))) + ''; xml += '<' + p + 'Resolution>' + escapeXml(String.valueOf(d.get('resolution'))) + ''; } xml += '' + deficiencies.size() + ''; } xml += ''; return xml; } private static String escapeXml(String s) { if (s == null) return ''; return s.replace('&', '&') .replace('<', '<') .replace('>', '>') .replace('"', '"') .replace('\'', '''); } private static CLMDocGenResponse parseTaskResponse(HttpResponse res) { Integer statusCode = res.getStatusCode(); String body = res.getBody(); if (statusCode >= 200 && statusCode < 300) { Map m = (Map) JSON.deserializeUntyped(body); String href = (String) m.get('Href'); String status = (String) m.get('Status'); String taskId = href != null ? href.substringAfterLast('/') : null; return new CLMDocGenResponse(true, 'Task status: ' + status, href, taskId); } else { return new CLMDocGenResponse(false, 'CLM API Error (HTTP ' + statusCode + '): ' + body, null, null); } } public class CLMDocGenResponse { public Boolean success; public String message; public String documentUrl; public String documentId; public CLMDocGenResponse(Boolean success, String message, String documentUrl, String documentId) { this.success = success; this.message = message; this.documentUrl = documentUrl; this.documentId = documentId; } } }