feat(esignature): add EnvelopeCreateResult class and createEnvelope() method
Adds EnvelopeCreateResult inner DTO and createEnvelope(Id, String, String)
to DocusignESignatureService. Option A (template-based): POSTs to
/v2.1/accounts/{accountId}/envelopes with templateId, templateRoles
(Signer), and status=sent. Guards blank templateId and blank appraiser
email; catches all exceptions and wraps in result. Named credential
sourced from CLM_Account_Setting__mdt per ADR-002.
Agent: claude-sonnet-4-6
Tests: 8/8 passing | N/A (no new test methods — Task 3 covers test coverage)
Tests-Added: 0
TypeScript: N/A (Apex project)
This commit is contained in:
parent
e4b7456dc1
commit
c3421e858f
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
- [x] **Task 1 — Custom fields:** Add 5 eSignature tracking fields to `Appraiser_Case__c` object metadata and update `package.xml` if needed. Deploy to verify. (FR-001)
|
- [x] **Task 1 — Custom fields:** Add 5 eSignature tracking fields to `Appraiser_Case__c` object metadata and update `package.xml` if needed. Deploy to verify. (FR-001)
|
||||||
|
|
||||||
- [ ] **Task 2 — EnvelopeCreateResult class + createEnvelope() method:** Add `EnvelopeCreateResult` inner class and `createEnvelope(Id caseId, String accountCode, String templateId)` to `DocusignESignatureService`. (FR-002)
|
- [x] **Task 2 — EnvelopeCreateResult class + createEnvelope() method:** Add `EnvelopeCreateResult` inner class and `createEnvelope(Id caseId, String accountCode, String templateId)` to `DocusignESignatureService`. (FR-002)
|
||||||
|
|
||||||
- [ ] **Task 3 — Tests for createEnvelope():** Add test coverage in `DocusignESignatureServiceTest` — success path (mock 201), failure path (mock 400), blank email guard. (NFR-001, TC-001, TC-002)
|
- [ ] **Task 3 — Tests for createEnvelope():** Add test coverage in `DocusignESignatureServiceTest` — success path (mock 201), failure path (mock 400), blank email guard. (NFR-001, TC-001, TC-002)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,14 @@ public with sharing class DocusignESignatureService {
|
||||||
@AuraEnabled public String rawJson;
|
@AuraEnabled public String rawJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class EnvelopeCreateResult {
|
||||||
|
@AuraEnabled public Boolean success;
|
||||||
|
@AuraEnabled public String envelopeId;
|
||||||
|
@AuraEnabled public String status;
|
||||||
|
@AuraEnabled public String envelopeUri;
|
||||||
|
@AuraEnabled public String errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
@AuraEnabled(cacheable=true)
|
@AuraEnabled(cacheable=true)
|
||||||
public static ESignatureAccountConfig getAccountConfig(String accountCode) {
|
public static ESignatureAccountConfig getAccountConfig(String accountCode) {
|
||||||
CLM_Account_Setting__mdt row = requireAccountSetting(accountCode);
|
CLM_Account_Setting__mdt row = requireAccountSetting(accountCode);
|
||||||
|
|
@ -144,6 +152,78 @@ public with sharing class DocusignESignatureService {
|
||||||
return parseEnvelopeList(response.responseBody);
|
return parseEnvelopeList(response.responseBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AuraEnabled(cacheable=false)
|
||||||
|
public static EnvelopeCreateResult createEnvelope(Id caseId, String accountCode, String templateId) {
|
||||||
|
EnvelopeCreateResult result = new EnvelopeCreateResult();
|
||||||
|
result.success = false;
|
||||||
|
try {
|
||||||
|
if (String.isBlank(templateId)) {
|
||||||
|
result.errorMessage = 'Template ID is required.';
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLM_Account_Setting__mdt row = requireAccountSetting(accountCode);
|
||||||
|
String targetAccountId = requireESignatureAccountId(row, accountCode, null);
|
||||||
|
|
||||||
|
Appraiser_Case__c caseRecord = [
|
||||||
|
SELECT Appraiser_Email__c,
|
||||||
|
Appraiser_Name__c,
|
||||||
|
Appraiser_Last_Name__c,
|
||||||
|
Appraiser_Salutation__c
|
||||||
|
FROM Appraiser_Case__c
|
||||||
|
WHERE Id = :caseId
|
||||||
|
LIMIT 1
|
||||||
|
];
|
||||||
|
|
||||||
|
if (String.isBlank(caseRecord.Appraiser_Email__c)) {
|
||||||
|
result.errorMessage = 'Appraiser email is blank on this case. Cannot create envelope.';
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String appraiserName = String.isNotBlank(caseRecord.Appraiser_Name__c)
|
||||||
|
? caseRecord.Appraiser_Name__c
|
||||||
|
: ((String.isNotBlank(caseRecord.Appraiser_Salutation__c)
|
||||||
|
? caseRecord.Appraiser_Salutation__c + ' '
|
||||||
|
: '') + String.valueOf(caseRecord.Appraiser_Last_Name__c)).trim();
|
||||||
|
|
||||||
|
Map<String, Object> roleMap = new Map<String, Object>{
|
||||||
|
'email' => caseRecord.Appraiser_Email__c,
|
||||||
|
'name' => appraiserName,
|
||||||
|
'roleName' => 'Signer'
|
||||||
|
};
|
||||||
|
Map<String, Object> bodyMap = new Map<String, Object>{
|
||||||
|
'templateId' => templateId,
|
||||||
|
'templateRoles' => new List<Object>{ roleMap },
|
||||||
|
'status' => 'sent'
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpRequest req = new HttpRequest();
|
||||||
|
req.setEndpoint(buildEndpoint(
|
||||||
|
'/v2.1/accounts/' + targetAccountId + '/envelopes',
|
||||||
|
row.ESignature_Rest_Named_Credential__c
|
||||||
|
));
|
||||||
|
req.setMethod('POST');
|
||||||
|
req.setHeader('Content-Type', 'application/json');
|
||||||
|
req.setTimeout(30000);
|
||||||
|
req.setBody(JSON.serialize(bodyMap));
|
||||||
|
|
||||||
|
HttpResponse res = new Http().send(req);
|
||||||
|
if (res.getStatusCode() >= 200 && res.getStatusCode() < 300) {
|
||||||
|
Map<String, Object> responseMap = (Map<String, Object>) JSON.deserializeUntyped(res.getBody());
|
||||||
|
result.success = true;
|
||||||
|
result.envelopeId = (String) responseMap.get('envelopeId');
|
||||||
|
result.status = (String) responseMap.get('status');
|
||||||
|
result.envelopeUri = (String) responseMap.get('uri');
|
||||||
|
} else {
|
||||||
|
result.errorMessage = 'eSignature API Error (HTTP ' + res.getStatusCode() + '): ' + res.getBody();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.success = false;
|
||||||
|
result.errorMessage = e.getMessage();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@TestVisible
|
@TestVisible
|
||||||
private static List<ESignatureAccountSummary> parseAccountList(String body) {
|
private static List<ESignatureAccountSummary> parseAccountList(String body) {
|
||||||
Object root = JSON.deserializeUntyped(body);
|
Object root = JSON.deserializeUntyped(body);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue