salesforce-appraiser-review.../docs/CLM_INTEGRATION.md

320 lines
11 KiB
Markdown

# CLM Doc Gen Integration Guide
> Status note (2026-04-07): the repo is now standardized on the XML merge path built on `AppraiserCasePayloadBuilder` and `CLMDocGenCallout`, using `Appraiser_Case_Deficiency__c` as the canonical child object. See `CURRENT_STATUS.md` before using this guide as the sole source of truth.
## Overview
This guide explains how to integrate Salesforce with DocuSign CLM to generate Appraiser Review Letters dynamically from Appraiser Case records.
---
## Architecture
### Components
1. **Salesforce Objects**: Appraiser_Case__c and Appraiser_Case_Deficiency__c
2. **Apex Payload Builder**: `AppraiserCasePayloadBuilder` - transforms SOQL data into CLM merge format
3. **HTTP Callout**: `CLMDocGenCallout` - invokes DocuSign CLM API
4. **CLM Template**: DocuSign CLM-hosted template with merge fields and repeat blocks
5. **Flow or Apex Trigger**: Orchestrates when/how document generation happens
### Data Flow
```
Appraiser Case (UI/API)
Salesforce Apex/Flow
AppraiserCasePayloadBuilder.buildPayload() [builds merge data]
CLMDocGenCallout.generateDocument() [sends to CLM API]
DocuSign CLM
Generated PDF + Envelope
Recipient Email
```
---
## Setup Steps
### 1. Configure Named Credentials (Salesforce)
**Goal**: Store CLM API endpoint and authentication credentials securely.
1. Go to Setup → Named Credentials → New
2. Configure:
- Label: `CLMNamedCred`
- URL: `https://[your-clm-instance].docusign.com`
- Authentication Protocol: `OAuth 2.0`
- Client ID: (from DocuSign CLM admin console)
- Client Secret: (from DocuSign CLM admin console)
- Scope: (typically `signature`)
- Token Endpoint: `https://[your-clm-instance].docusign.com/oauth/token`
3. Save
**Alternative**: For testing, use a custom Named Credential with API Key auth if available from your CLM admin.
### 2. Configure Remote Site Settings (Salesforce)
**Goal**: Whitelist CLM domain for HTTP callouts.
1. Go to Setup → Remote Site Settings → New
2. Configure:
- Remote Site Name: `DocuSignCLM`
- Remote Site URL: `https://[your-clm-instance].docusign.com`
- Disable Protocol Security: (unchecked for production)
3. Save
### 3. Get CLM Template ID
**Goal**: Identify which CLM template to use for Appraiser Review Letters.
1. In DocuSign CLM admin console, navigate to Templates
2. Find or create the Appraiser Review Letter template
3. Note the Template ID (usually a UUID or numeric string)
4. Verify the template expects these merge fields:
- `AppraiserCaseNumber` (Text)
- `AppraiserFieldReviewDate` (Date)
- `PropertyAddress` (Text)
- `DeficiencyList[]` (Array/Lines table with deficiencyNumber, description, resolution)
---
## Usage Patterns
### Pattern 1: Queueable Apex (Automatic/Trigger-Driven)
**Scenario**: Generate letter automatically from a trigger or process (callouts cannot be made synchronously from triggers — use a queueable)
```apex
public class AppraiserCaseDocGenJob implements Queueable, Database.AllowsCallouts {
private Id caseId;
private String accountCode;
private String templateDocHref;
private String destinationFolderHref;
private String destinationDocName;
public AppraiserCaseDocGenJob(Id caseId, String accountCode,
String templateDocHref, String destinationFolderHref, String destinationDocName) {
this.caseId = caseId;
this.accountCode = accountCode;
this.templateDocHref = templateDocHref;
this.destinationFolderHref = destinationFolderHref;
this.destinationDocName = destinationDocName;
}
public void execute(QueueableContext ctx) {
CLMDocGenCallout.CLMDocGenResponse response = CLMAdminService.generateDocument(
caseId, templateDocHref, destinationFolderHref, destinationDocName, accountCode
);
if (!response.success) {
System.debug('CLM Doc Gen failed: ' + response.message);
}
}
}
// Enqueue from a trigger:
System.enqueueJob(new AppraiserCaseDocGenJob(
record.Id,
'DTC_CLM_Demo',
letterSettings.defaultTemplateDocumentHref,
letterSettings.destinationRootFolderHref,
'Review_' + record.Name + '.docx'
));
```
### Pattern 2: LWC Quick Action (UI-Driven) ✅ Implemented
The `clmDocGenWorkbench` component, launched from the **Generate Review Letter** quick action, is the current implemented UI path. It calls `CLMAdminService` to:
- Browse available accounts and letter types
- Browse CLM template and destination folders
- Submit a merge task via `generateDocument()`
- Poll task status via `getTaskStatus()`
- Attach the generated file to the case via `attachGeneratedDocumentToCase()`
No additional configuration is needed beyond deploying the metadata and setting up Named Credentials.
### Pattern 3: REST API (External System)
**Scenario**: External system calls Salesforce to generate letter
```apex
@RestResource(urlMapping='/appraiser-case-generate-letter')
global class AppraiserCaseDocGenRest {
@HttpPost
global static void generateLetter(
String caseId,
String accountCode,
String templateDocHref,
String destinationFolderHref,
String destinationDocName
) {
CLMDocGenCallout.CLMDocGenResponse response = CLMAdminService.generateDocument(
(Id) caseId, templateDocHref, destinationFolderHref, destinationDocName, accountCode
);
RestContext.response.statusCode = response.success ? 200 : 400;
RestContext.response.responseBody = Blob.valueOf(JSON.serialize(response));
}
}
```
---
## Payload Structure
### AppraiserCasePayloadBuilder output (intermediate JSON)
```json
{
"AppraiserCaseNumber": "AC-000001",
"AppraiserFieldReviewDate": "Apr 02, 2026",
"LetterSentDate": "Apr 09, 2026",
"FHACaseNumber": "123-4567890",
"AppraiserName": "Jamie Appraiser",
"AppraiserSalutation": "Ms.",
"AppraiserLastName": "Appraiser",
"AppraiserEmail": "jamie@example.com",
"AppraiserAddress": "245 Lexington Ave, New York, NY 10016, USA",
"PropertyAddress": "123 Main St, Denver, CO 80202, USA",
"DeficiencyList": [
{ "deficiencyNumber": 1, "description": "...", "resolution": "...", "reference": "VC-1" }
]
}
```
### CLM API Request (what CLMDocGenCallout sends to `/documentxmlmergetasks`)
```json
{
"TemplateDocument": { "Href": "https://.../documents/<template-guid>" },
"DataXML": "<TemplateFieldData><AppraiserCaseNumber>AC-000001</AppraiserCaseNumber>...<DeficiencyList><Deficiency><Number>1</Number>...</Deficiency></DeficiencyList></TemplateFieldData>",
"DestinationDocumentName": "Review_AC-000001.docx",
"DestinationFolder": { "Href": "https://.../folders/<folder-guid>" }
}
```
### CLM API Response (on success)
```json
{
"Href": "https://apiuatna11.springcm.com/v2/<account-id>/documentxmlmergetasks/<task-guid>",
"Status": "Queued",
"Result": { "Href": "https://apiuatna11.springcm.com/v2/<account-id>/documents/<doc-guid>" }
}
```
The response is persisted to `Appraiser_Case__c` tracking fields by `CLMAdminService.persistDocGenResult()`.
---
## CLM Template Design
The implementation uses the DocuSign CLM **XML merge** (`documentxmlmergetasks`) API, not a Handlebars/template-key approach. Template field tags in the `.docx` file use CLM's Word merge syntax (typically `«FieldName»` merge fields or CLM repeat-block markers). Refer to your CLM tenant documentation for the exact syntax.
**Flat field example** (Word merge field in the .docx):
```
«AppraiserCaseNumber» «AppraiserFieldReviewDate»
«PropertyAddress»
```
**Deficiency repeat block** — the XML structure sent is:
```xml
<DeficiencyList>
<Deficiency>
<Number>1</Number>
<Description>Missing comparable sale adjustment detail.</Description>
<Resolution>Added adjustment rationale and supporting calculations.</Resolution>
<Reference>VC-1</Reference>
</Deficiency>
</DeficiencyList>
<DeficiencyCount>1</DeficiencyCount>
```
Configure a repeat region in your CLM template over `DeficiencyList/Deficiency`, binding `Number`, `Description`, `Resolution`, and `Reference` within the loop.
---
## Testing
### Unit Test (Apex)
```bash
sf apex run test --test-level RunLocalTests --target-org appraiser-dev
```
Expected: AppraiserCasePayloadBuilderTest passes all assertions.
### Integration Test (Manual)
1. In Salesforce, create an Appraiser Case with 2-3 sample deficiencies
2. Run (in Apex Execute):
```apex
String caseId = 'a0wKW000007OIiCYAW';
Map<String, Object> payload = AppraiserCasePayloadBuilder.buildPayload(caseId);
System.debug(JSON.serialize(payload));
```
3. Copy payload output
4. Verify all fields and DeficiencyList array are populated
### CLM Integration Test
1. Set up Named Credentials and Remote Site Settings (see Setup section)
2. Configure CLM template ID in CLMDocGenCallout
3. Run (in Apex Execute):
```apex
String caseId = 'a0wKW000007OIiCYAW';
String templateId = 'TEMPLATE_123';
String recipientEmail = 'test@example.com';
CLMDocGenCallout.CLMDocGenResponse response = CLMDocGenCallout.generateDocument(
caseId, templateId, recipientEmail
);
System.debug('Success: ' + response.success);
System.debug('Message: ' + response.message);
System.debug('Document URL: ' + response.documentUrl);
```
4. Monitor CLM instance for outbound document delivery
---
## Troubleshooting
### "Document generated successfully" but no email received
- Check recipient email in CLM settings (delivery rules may have delay)
- Verify Email-to-Sign integration is enabled in CLM
- Check CLM audit log for delivery status
### HTTP 401 Unauthorized (Named Credentials)
- Verify OAuth token is valid in Named Credentials
- Refresh token or re-authorize
- Check OAuth scope matches CLM permissions
### "Appraiser Case not found" error
- Verify record ID is correct
- Ensure Appraiser_Case__c object permissions are granted to running user
### Empty DeficiencyList in generated document
- Check that related Appraiser_Case_Deficiency__c records exist
- Verify CLM template correctly references {{DeficiencyList}}
- Test payload in Apex to confirm array is populated
---
## Performance Notes
- `AppraiserCasePayloadBuilder.buildPayload()` runs one query (with related records in subquery)
- `CLMDocGenCallout.generateDocument()` performs one HTTP callout (blocks execution ~1-5 seconds)
- For bulk operations, consider queueable jobs or batch class to manage API rate limits
---
## Next Steps
1. ✅ Deploy Apex classes to org (included in manifest)
2. Configure Named Credentials with CLM OAuth/API credentials
3. Add CLM Template ID to CLMDocGenCallout (configurable constant or custom setting)
4. Build a Flow or Trigger to invoke CLMDocGenCallout
5. Test end-to-end with sample Appraiser Case records
---
_Last updated: 2026-04-02_
_Updated to include setup instructions and integration patterns._