salesforce-appraiser-review.../force-app/main/default/classes/CLMAdminService.cls

745 lines
32 KiB
OpenEdge ABL

public with sharing class CLMAdminService {
public class CaseDeficiencyItem {
@AuraEnabled public Id recordId;
@AuraEnabled public Decimal deficiencyNumber;
@AuraEnabled public String description;
@AuraEnabled public String resolution;
@AuraEnabled public String reference;
}
public class CaseContext {
@AuraEnabled public Id caseId;
@AuraEnabled public String caseNumber;
@AuraEnabled public String propertyAddress;
@AuraEnabled public String lastDocGenStatus;
@AuraEnabled public String lastDocGenMessage;
@AuraEnabled public String lastClmAccountCode;
@AuraEnabled public String lastDocGenTaskId;
@AuraEnabled public String lastDocGenTaskUrl;
@AuraEnabled public String generatedDocumentUrl;
@AuraEnabled public String generatedDocumentId;
@AuraEnabled public String attachedFileContentDocumentId;
@AuraEnabled public String attachedFileUrl;
@AuraEnabled public Datetime lastDocGenRequestedAt;
@AuraEnabled public Datetime lastDocGenCompletedAt;
@AuraEnabled public List<CaseDeficiencyItem> deficiencies;
}
public class FileAttachmentResult {
@AuraEnabled public Boolean success;
@AuraEnabled public String message;
@AuraEnabled public String contentDocumentId;
@AuraEnabled public String fileUrl;
@AuraEnabled public String fileTitle;
}
public class AccountSettings {
@AuraEnabled public String accountCode;
@AuraEnabled public String accountDisplayName;
@AuraEnabled public String environment;
@AuraEnabled public String clmAccountId;
@AuraEnabled public String clmApiNamedCredential;
@AuraEnabled public String clmDownloadNamedCredential;
@AuraEnabled public String eSignatureRestNamedCredential;
@AuraEnabled public String templateRootFolderHref;
@AuraEnabled public String destinationRootFolderHref;
@AuraEnabled public String defaultTemplateDocumentHref;
@AuraEnabled public String defaultDocumentNamePrefix;
@AuraEnabled public Boolean active;
}
public class LetterSettings {
@AuraEnabled public String accountCode;
@AuraEnabled public String letterCode;
@AuraEnabled public String letterDisplayName;
@AuraEnabled public String description;
@AuraEnabled public Boolean isDefault;
@AuraEnabled public Decimal sortOrder;
@AuraEnabled public String templateRootFolderHref;
@AuraEnabled public String destinationRootFolderHref;
@AuraEnabled public String defaultTemplateDocumentHref;
@AuraEnabled public String defaultDocumentNamePrefix;
@AuraEnabled public Boolean active;
}
public class ResourceItem {
@AuraEnabled public String name;
@AuraEnabled public String href;
@AuraEnabled public String type;
@AuraEnabled public String parentHref;
@AuraEnabled public String rawJson;
}
public class FolderContents {
@AuraEnabled public ResourceItem folder;
@AuraEnabled public List<ResourceItem> folders;
@AuraEnabled public List<ResourceItem> documents;
}
public class DocGenPreview {
@AuraEnabled public String accountCode;
@AuraEnabled public String accountDisplayName;
@AuraEnabled public String letterCode;
@AuraEnabled public String letterDisplayName;
@AuraEnabled public String mergeTaskEndpointUrl;
@AuraEnabled public String templateDocHref;
@AuraEnabled public String destinationFolderHref;
@AuraEnabled public String destinationDocName;
@AuraEnabled public String payloadJson;
@AuraEnabled public String dataXml;
@AuraEnabled public String requestBodyJson;
}
@AuraEnabled(cacheable=true)
public static List<AccountSettings> listAccountSettings() {
List<AccountSettings> settings = new List<AccountSettings>();
for (CLM_Account_Setting__mdt row : [
SELECT DeveloperName,
Account_Code__c,
Account_Display_Name__c,
Environment_Code__c,
CLM_Account_Id__c,
CLM_Api_Named_Credential__c,
CLM_Download_Named_Credential__c,
ESignature_Rest_Named_Credential__c,
Template_Root_Folder_Href__c,
Destination_Root_Folder_Href__c,
Default_Template_Document_Href__c,
Default_Destination_Document_Name_Prefix__c,
Active__c
FROM CLM_Account_Setting__mdt
WHERE Active__c = true
ORDER BY Account_Display_Name__c ASC, DeveloperName ASC
]) {
settings.add(toAccountSettings(row));
}
return settings;
}
@AuraEnabled(cacheable=true)
public static AccountSettings getAccountSettings(String accountCode) {
CLM_Account_Setting__mdt row = resolveAccountSetting(accountCode);
return row == null ? null : toAccountSettings(row);
}
@AuraEnabled(cacheable=true)
public static List<LetterSettings> listLetterSettings(String accountCode) {
AccountSettings account = getAccountSettings(accountCode);
List<LetterSettings> letters = new List<LetterSettings>();
if (account == null) {
return letters;
}
for (CLM_Letter_Definition__mdt row : [
SELECT DeveloperName,
Account_Code__c,
Letter_Code__c,
Letter_Display_Name__c,
Description__c,
Active__c,
Is_Default__c,
Sort_Order__c,
Template_Root_Folder_Href__c,
Destination_Root_Folder_Href__c,
Default_Template_Document_Href__c,
Default_Destination_Document_Name_Prefix__c
FROM CLM_Letter_Definition__mdt
WHERE Active__c = true
AND Account_Code__c = :account.accountCode
ORDER BY Is_Default__c DESC, Sort_Order__c ASC, Letter_Display_Name__c ASC, DeveloperName ASC
]) {
letters.add(toLetterSettings(row, account));
}
if (letters.isEmpty()) {
letters.add(buildFallbackLetterSettings(account));
}
return letters;
}
@AuraEnabled(cacheable=true)
public static LetterSettings getLetterSettings(String accountCode, String letterCode) {
AccountSettings account = getAccountSettings(accountCode);
if (account == null) {
return null;
}
String normalizedLetterCode = String.isBlank(letterCode) ? null : letterCode.trim();
if (String.isNotBlank(normalizedLetterCode)) {
List<CLM_Letter_Definition__mdt> rows = [
SELECT DeveloperName,
Account_Code__c,
Letter_Code__c,
Letter_Display_Name__c,
Description__c,
Active__c,
Is_Default__c,
Sort_Order__c,
Template_Root_Folder_Href__c,
Destination_Root_Folder_Href__c,
Default_Template_Document_Href__c,
Default_Destination_Document_Name_Prefix__c
FROM CLM_Letter_Definition__mdt
WHERE Active__c = true
AND Account_Code__c = :account.accountCode
AND Letter_Code__c = :normalizedLetterCode
LIMIT 1
];
if (!rows.isEmpty()) {
return toLetterSettings(rows[0], account);
}
}
List<LetterSettings> letters = listLetterSettings(account.accountCode);
for (LetterSettings letter : letters) {
if (letter.isDefault) {
return letter;
}
}
return letters.isEmpty() ? buildFallbackLetterSettings(account) : letters[0];
}
@AuraEnabled(cacheable=false)
public static CLMDocGenCallout.CLMDocGenResponse generateDocument(
Id appraiserCaseId,
String templateDocHref,
String destinationFolderHref,
String destinationDocName,
String accountCode
) {
CLM_Account_Setting__mdt account = requireAccountSetting(accountCode);
CLMDocGenCallout.CLMDocGenResponse response = CLMDocGenCallout.generateDocument(
(String) appraiserCaseId,
templateDocHref,
destinationFolderHref,
destinationDocName,
account.Environment_Code__c,
account.CLM_Account_Id__c,
account.CLM_Api_Named_Credential__c
);
persistDocGenResult(appraiserCaseId, templateDocHref, destinationFolderHref, response, false, accountCode);
return response;
}
@AuraEnabled(cacheable=false)
public static CLMDocGenCallout.CLMDocGenResponse getTaskStatus(Id appraiserCaseId, String taskId, String accountCode) {
CLM_Account_Setting__mdt account = requireAccountSetting(accountCode);
CLMDocGenCallout.CLMDocGenResponse response = CLMDocGenCallout.getTaskStatus(
taskId,
account.Environment_Code__c,
account.CLM_Account_Id__c,
account.CLM_Api_Named_Credential__c
);
persistDocGenResult(appraiserCaseId, null, null, response, true, accountCode);
return response;
}
@AuraEnabled(cacheable=false)
public static String probeResource(String resourceOrHref, String accountCode) {
CLM_Account_Setting__mdt account = requireAccountSetting(accountCode);
return performGet(resourceOrHref, account).getBody();
}
@AuraEnabled(cacheable=false)
public static DocGenPreview getDocGenPreview(Id appraiserCaseId, String accountCode, String letterCode) {
if (appraiserCaseId == null) {
throw new AuraHandledException('appraiserCaseId is required');
}
AccountSettings account = getAccountSettings(accountCode);
if (account == null) {
throw new AuraHandledException('No active CLM account setting was found for ' + accountCode + '.');
}
LetterSettings letter = getLetterSettings(account.accountCode, letterCode);
List<Appraiser_Case__c> previewRows = [
SELECT Id, Name
FROM Appraiser_Case__c
WHERE Id = :appraiserCaseId
LIMIT 1
];
if (previewRows.isEmpty()) {
throw new AuraHandledException('Appraiser Case not found: ' + appraiserCaseId);
}
Appraiser_Case__c appraiserCase = previewRows[0];
String prefix = letter != null && String.isNotBlank(letter.defaultDocumentNamePrefix)
? letter.defaultDocumentNamePrefix
: account.defaultDocumentNamePrefix;
DocGenPreview preview = new DocGenPreview();
preview.accountCode = account.accountCode;
preview.accountDisplayName = account.accountDisplayName;
preview.letterCode = letter != null ? letter.letterCode : 'APPRAISER_REVIEW';
preview.letterDisplayName = letter != null ? letter.letterDisplayName : 'Appraiser Review Letter';
preview.templateDocHref = letter != null ? letter.defaultTemplateDocumentHref : account.defaultTemplateDocumentHref;
preview.destinationFolderHref = letter != null ? letter.destinationRootFolderHref : account.destinationRootFolderHref;
preview.destinationDocName = buildDefaultDocumentName(prefix, appraiserCase.Name);
preview.mergeTaskEndpointUrl = CLMDocGenCallout.buildDocumentXmlMergeTasksUrl(
preview.templateDocHref,
preview.destinationFolderHref,
account.environment,
account.clmAccountId
);
preview.payloadJson = JSON.serializePretty(AppraiserCasePayloadBuilder.buildPayload((String) appraiserCaseId));
preview.dataXml = CLMDocGenCallout.prettyPrintXml(CLMDocGenCallout.buildDataXmlForCase((String) appraiserCaseId));
preview.requestBodyJson = CLMDocGenCallout.buildRequestBodyJson(
(String) appraiserCaseId,
preview.templateDocHref,
preview.destinationFolderHref,
preview.destinationDocName
);
return preview;
}
@AuraEnabled(cacheable=false)
public static CaseContext getCaseContext(Id appraiserCaseId) {
List<Appraiser_Case__c> contextRows = [
SELECT Id,
Name,
Property_Street__c,
Property_City__c,
Property_State_Province__c,
Property_Postal_Code__c,
Property_Country__c,
Last_DocGen_Status__c,
Last_DocGen_Message__c,
Last_CLM_Account_Code__c,
Last_DocGen_Task_Id__c,
Last_DocGen_Task_Url__c,
Generated_Document_Url__c,
Generated_Document_Id__c,
Attached_File_Content_Document_Id__c,
Attached_File_Url__c,
Last_DocGen_Requested_At__c,
Last_DocGen_Completed_At__c,
(SELECT Id,
Deficiency_Number__c,
Description__c,
Resolution__c,
Reference__c
FROM Deficiencies__r
ORDER BY Deficiency_Number__c ASC, CreatedDate ASC)
FROM Appraiser_Case__c
WHERE Id = :appraiserCaseId
LIMIT 1
];
if (contextRows.isEmpty()) {
throw new AuraHandledException('Appraiser Case not found: ' + appraiserCaseId);
}
Appraiser_Case__c appraiserCase = contextRows[0];
CaseContext context = new CaseContext();
context.caseId = appraiserCase.Id;
context.caseNumber = appraiserCase.Name;
context.propertyAddress = formatAddress(appraiserCase);
context.lastDocGenStatus = appraiserCase.Last_DocGen_Status__c;
context.lastDocGenMessage = appraiserCase.Last_DocGen_Message__c;
context.lastClmAccountCode = appraiserCase.Last_CLM_Account_Code__c;
context.lastDocGenTaskId = appraiserCase.Last_DocGen_Task_Id__c;
context.lastDocGenTaskUrl = appraiserCase.Last_DocGen_Task_Url__c;
context.generatedDocumentUrl = appraiserCase.Generated_Document_Url__c;
context.generatedDocumentId = appraiserCase.Generated_Document_Id__c;
context.attachedFileContentDocumentId = appraiserCase.Attached_File_Content_Document_Id__c;
context.attachedFileUrl = appraiserCase.Attached_File_Url__c;
context.lastDocGenRequestedAt = appraiserCase.Last_DocGen_Requested_At__c;
context.lastDocGenCompletedAt = appraiserCase.Last_DocGen_Completed_At__c;
context.deficiencies = new List<CaseDeficiencyItem>();
if (appraiserCase.Deficiencies__r != null) {
for (Appraiser_Case_Deficiency__c deficiency : appraiserCase.Deficiencies__r) {
CaseDeficiencyItem item = new CaseDeficiencyItem();
item.recordId = deficiency.Id;
item.deficiencyNumber = deficiency.Deficiency_Number__c;
item.description = deficiency.Description__c;
item.resolution = deficiency.Resolution__c;
item.reference = deficiency.Reference__c;
context.deficiencies.add(item);
}
}
return context;
}
@AuraEnabled(cacheable=false)
public static FileAttachmentResult attachGeneratedDocumentToCase(Id appraiserCaseId, String accountCode) {
if (appraiserCaseId == null) {
throw new AuraHandledException('appraiserCaseId is required');
}
CLM_Account_Setting__mdt account = requireAccountSetting(accountCode);
Appraiser_Case__c appraiserCase = [
SELECT Id,
Name,
Generated_Document_Url__c,
Generated_Document_Id__c
FROM Appraiser_Case__c
WHERE Id = :appraiserCaseId
LIMIT 1
];
if (String.isBlank(appraiserCase.Generated_Document_Url__c)) {
throw new AuraHandledException('No generated document is available to attach yet.');
}
CLMDocGenCallout.DownloadedDocument downloaded = CLMDocGenCallout.downloadDocument(
appraiserCase.Generated_Document_Url__c,
account.Environment_Code__c,
account.CLM_Account_Id__c,
account.CLM_Download_Named_Credential__c
);
String fileName = String.isNotBlank(downloaded.fileName)
? downloaded.fileName
: 'Generated_' + appraiserCase.Name + '.docx';
String title = fileName.contains('.')
? fileName.substringBeforeLast('.')
: fileName;
ContentVersion version = new ContentVersion(
Title = title,
PathOnClient = '/' + fileName,
VersionData = downloaded.body
);
insert version;
version = [
SELECT Id, ContentDocumentId
FROM ContentVersion
WHERE Id = :version.Id
LIMIT 1
];
insert new ContentDocumentLink(
ContentDocumentId = version.ContentDocumentId,
LinkedEntityId = appraiserCase.Id,
ShareType = 'V',
Visibility = 'AllUsers'
);
String fileUrl = '/lightning/r/ContentDocument/' + version.ContentDocumentId + '/view';
update new Appraiser_Case__c(
Id = appraiserCase.Id,
Last_CLM_Account_Code__c = accountCode,
Attached_File_Content_Document_Id__c = version.ContentDocumentId,
Attached_File_Url__c = fileUrl
);
FileAttachmentResult result = new FileAttachmentResult();
result.success = true;
result.message = 'Generated document attached to the case.';
result.contentDocumentId = version.ContentDocumentId;
result.fileUrl = fileUrl;
result.fileTitle = title;
return result;
}
private static String formatAddress(Appraiser_Case__c appraiserCase) {
return AppraiserCasePayloadBuilder.formatMailingAddress(
appraiserCase.Property_Street__c,
appraiserCase.Property_City__c,
appraiserCase.Property_State_Province__c,
appraiserCase.Property_Postal_Code__c,
appraiserCase.Property_Country__c
);
}
@AuraEnabled(cacheable=false)
public static FolderContents getFolderContents(String folderHref, String accountCode) {
if (String.isBlank(folderHref)) {
throw new IllegalArgumentException('folderHref is required');
}
CLM_Account_Setting__mdt account = requireAccountSetting(accountCode);
FolderContents contents = new FolderContents();
contents.folder = parseSingleResource(performGet(folderHref, account).getBody(), 'Folder');
contents.folders = parseResourceList(performGet(folderHref + '/folders', account).getBody(), 'Folder', folderHref);
contents.documents = parseResourceList(performGet(folderHref + '/documents', account).getBody(), 'Document', folderHref);
return contents;
}
private static HttpResponse performGet(String resourceOrHref, CLM_Account_Setting__mdt account) {
HttpRequest req = new HttpRequest();
req.setEndpoint(CLMDocGenCallout.buildEndpointForResource(
resourceOrHref,
account.CLM_Account_Id__c,
account.CLM_Api_Named_Credential__c
));
req.setMethod('GET');
req.setTimeout(CLMDocGenCallout.HTTP_TIMEOUT);
HttpResponse res = new Http().send(req);
Integer statusCode = res.getStatusCode();
if (statusCode < 200 || statusCode >= 300) {
throw new AuraHandledException('CLM API Error (HTTP ' + statusCode + '): ' + res.getBody());
}
return res;
}
@TestVisible
private static ResourceItem parseSingleResource(String body, String defaultType) {
Object root = JSON.deserializeUntyped(body);
if (!(root instanceof Map<String, Object>)) {
return null;
}
return parseResource((Map<String, Object>) root, defaultType, null);
}
@TestVisible
private static List<ResourceItem> parseResourceList(String body, String defaultType, String parentHref) {
Object root = JSON.deserializeUntyped(body);
List<Object> records = unwrapList(root);
List<ResourceItem> items = new List<ResourceItem>();
for (Object record : records) {
if (record instanceof Map<String, Object>) {
items.add(parseResource((Map<String, Object>) record, defaultType, parentHref));
}
}
return items;
}
private static List<Object> unwrapList(Object root) {
if (root instanceof List<Object>) {
return (List<Object>) root;
}
if (root instanceof Map<String, Object>) {
Map<String, Object> payload = (Map<String, Object>) root;
for (String key : new List<String>{ 'Results', 'Items', 'Documents', 'Folders' }) {
Object value = payload.get(key);
if (value instanceof List<Object>) {
return (List<Object>) value;
}
}
if (payload.size() == 1) {
for (Object value : payload.values()) {
if (value instanceof List<Object>) {
return (List<Object>) value;
}
}
}
}
return new List<Object>();
}
private static ResourceItem parseResource(Map<String, Object> source, String defaultType, String parentHref) {
ResourceItem item = new ResourceItem();
item.name = firstString(source, new List<String>{ 'Name', 'DisplayName', 'Title', 'Label' });
item.href = firstString(source, new List<String>{ 'Href', 'Uri', 'Location' });
item.type = firstString(source, new List<String>{ 'Type', 'ObjectType', 'ItemType' });
item.parentHref = extractParentHref(source, parentHref);
item.rawJson = JSON.serialize(source);
if (String.isBlank(item.type)) {
item.type = defaultType;
}
if (String.isBlank(item.name) && String.isNotBlank(item.href)) {
item.name = item.href.substringAfterLast('/');
}
return item;
}
private static String extractParentHref(Map<String, Object> source, String fallbackValue) {
Object parentValue = source.get('Parent');
if (parentValue instanceof Map<String, Object>) {
String href = firstString((Map<String, Object>) parentValue, new List<String>{ 'Href', 'Uri', 'Location' });
if (String.isNotBlank(href)) {
return href;
}
}
return fallbackValue;
}
private static String firstString(Map<String, Object> source, List<String> keys) {
for (String key : keys) {
Object value = source.get(key);
if (value != null) {
String textValue = String.valueOf(value);
if (String.isNotBlank(textValue)) {
return textValue;
}
}
}
return null;
}
private static void persistDocGenResult(
Id appraiserCaseId,
String templateDocHref,
String destinationFolderHref,
CLMDocGenCallout.CLMDocGenResponse response,
Boolean isStatusRefresh,
String accountCode
) {
if (appraiserCaseId == null || response == null) {
return;
}
Appraiser_Case__c updateCase = new Appraiser_Case__c(Id = appraiserCaseId);
updateCase.Last_CLM_Account_Code__c = accountCode;
updateCase.Last_DocGen_Status__c = String.isNotBlank(response.taskStatus) ? response.taskStatus : (response.success ? 'Submitted' : 'Failed');
updateCase.Last_DocGen_Message__c = response.message;
updateCase.Last_DocGen_Task_Id__c = response.documentId;
updateCase.Last_DocGen_Task_Url__c = response.documentUrl;
if (!isStatusRefresh) {
updateCase.Last_DocGen_Requested_At__c = System.now();
updateCase.Last_Template_Document_Href__c = templateDocHref;
updateCase.Last_Destination_Folder_Href__c = destinationFolderHref;
}
if (String.isNotBlank(response.generatedDocumentUrl)) {
updateCase.Generated_Document_Url__c = response.generatedDocumentUrl;
updateCase.Generated_Document_Id__c = response.generatedDocumentId;
}
if (response.success && String.valueOf(response.taskStatus).toLowerCase() == 'completed') {
updateCase.Last_DocGen_Completed_At__c = System.now();
}
update updateCase;
}
private static CLM_Account_Setting__mdt requireAccountSetting(String accountCode) {
CLM_Account_Setting__mdt row = resolveAccountSetting(accountCode);
if (row == null) {
throw new AuraHandledException('No active CLM account setting was found for ' + accountCode + '.');
}
return row;
}
private static CLM_Account_Setting__mdt resolveAccountSetting(String accountCode) {
String normalizedCode = String.isBlank(accountCode) ? null : accountCode.trim();
List<CLM_Account_Setting__mdt> rows;
if (String.isNotBlank(normalizedCode)) {
rows = [
SELECT DeveloperName,
Account_Code__c,
Account_Display_Name__c,
Environment_Code__c,
CLM_Account_Id__c,
CLM_Api_Named_Credential__c,
CLM_Download_Named_Credential__c,
ESignature_Rest_Named_Credential__c,
Template_Root_Folder_Href__c,
Destination_Root_Folder_Href__c,
Default_Template_Document_Href__c,
Default_Destination_Document_Name_Prefix__c,
Active__c
FROM CLM_Account_Setting__mdt
WHERE Active__c = true
AND DeveloperName = :normalizedCode
LIMIT 1
];
if (rows.isEmpty()) {
rows = [
SELECT DeveloperName,
Account_Code__c,
Account_Display_Name__c,
Environment_Code__c,
CLM_Account_Id__c,
CLM_Api_Named_Credential__c,
CLM_Download_Named_Credential__c,
ESignature_Rest_Named_Credential__c,
Template_Root_Folder_Href__c,
Destination_Root_Folder_Href__c,
Default_Template_Document_Href__c,
Default_Destination_Document_Name_Prefix__c,
Active__c
FROM CLM_Account_Setting__mdt
WHERE Active__c = true
AND Account_Code__c = :normalizedCode
LIMIT 1
];
}
} else {
rows = [
SELECT DeveloperName,
Account_Code__c,
Account_Display_Name__c,
Environment_Code__c,
CLM_Account_Id__c,
CLM_Api_Named_Credential__c,
CLM_Download_Named_Credential__c,
ESignature_Rest_Named_Credential__c,
Template_Root_Folder_Href__c,
Destination_Root_Folder_Href__c,
Default_Template_Document_Href__c,
Default_Destination_Document_Name_Prefix__c,
Active__c
FROM CLM_Account_Setting__mdt
WHERE Active__c = true
ORDER BY Account_Display_Name__c ASC, DeveloperName ASC
LIMIT 1
];
}
return rows.isEmpty() ? null : rows[0];
}
private static AccountSettings toAccountSettings(CLM_Account_Setting__mdt row) {
AccountSettings settings = new AccountSettings();
settings.accountCode = String.isNotBlank(row.Account_Code__c) ? row.Account_Code__c : row.DeveloperName;
settings.accountDisplayName = String.isNotBlank(row.Account_Display_Name__c) ? row.Account_Display_Name__c : row.DeveloperName;
settings.environment = row.Environment_Code__c;
settings.clmAccountId = row.CLM_Account_Id__c;
settings.clmApiNamedCredential = row.CLM_Api_Named_Credential__c;
settings.clmDownloadNamedCredential = row.CLM_Download_Named_Credential__c;
settings.eSignatureRestNamedCredential = row.ESignature_Rest_Named_Credential__c;
settings.templateRootFolderHref = row.Template_Root_Folder_Href__c;
settings.destinationRootFolderHref = row.Destination_Root_Folder_Href__c;
settings.defaultTemplateDocumentHref = row.Default_Template_Document_Href__c;
settings.defaultDocumentNamePrefix = row.Default_Destination_Document_Name_Prefix__c;
settings.active = row.Active__c;
return settings;
}
private static LetterSettings toLetterSettings(CLM_Letter_Definition__mdt row, AccountSettings account) {
LetterSettings settings = new LetterSettings();
settings.accountCode = String.isNotBlank(row.Account_Code__c) ? row.Account_Code__c : account.accountCode;
settings.letterCode = String.isNotBlank(row.Letter_Code__c) ? row.Letter_Code__c : 'APPRAISER_REVIEW';
settings.letterDisplayName = String.isNotBlank(row.Letter_Display_Name__c) ? row.Letter_Display_Name__c : row.DeveloperName;
settings.description = row.Description__c;
settings.isDefault = row.Is_Default__c;
settings.sortOrder = row.Sort_Order__c;
settings.templateRootFolderHref = firstNonBlankValue(row.Template_Root_Folder_Href__c, account.templateRootFolderHref);
settings.destinationRootFolderHref = firstNonBlankValue(row.Destination_Root_Folder_Href__c, account.destinationRootFolderHref);
settings.defaultTemplateDocumentHref = firstNonBlankValue(row.Default_Template_Document_Href__c, account.defaultTemplateDocumentHref);
settings.defaultDocumentNamePrefix = firstNonBlankValue(row.Default_Destination_Document_Name_Prefix__c, account.defaultDocumentNamePrefix);
settings.active = row.Active__c;
return settings;
}
private static LetterSettings buildFallbackLetterSettings(AccountSettings account) {
LetterSettings settings = new LetterSettings();
settings.accountCode = account.accountCode;
settings.letterCode = 'APPRAISER_REVIEW';
settings.letterDisplayName = 'Appraiser Review Letter';
settings.description = 'Fallback current appraiser letter flow.';
settings.isDefault = true;
settings.sortOrder = 10;
settings.templateRootFolderHref = account.templateRootFolderHref;
settings.destinationRootFolderHref = account.destinationRootFolderHref;
settings.defaultTemplateDocumentHref = account.defaultTemplateDocumentHref;
settings.defaultDocumentNamePrefix = account.defaultDocumentNamePrefix;
settings.active = true;
return settings;
}
private static String firstNonBlankValue(String preferredValue, String fallbackValue) {
return String.isNotBlank(preferredValue) ? preferredValue : fallbackValue;
}
private static String buildDefaultDocumentName(String prefix, String caseNumber) {
String normalizedPrefix = String.isNotBlank(prefix) ? prefix : 'Review';
return String.isNotBlank(caseNumber)
? normalizedPrefix + '_' + caseNumber + '.docx'
: normalizedPrefix + '.docx';
}
}