The IOrganizationPartyManagementDELETE interface provides extensibility for DELETE operations through Apex-based validations, mutation-payload adjustments, and post-operation processing. Users can enforce deletion policies, apply soft-delete or metadata logic, and customize final responses without impacting TMF-compliant delete behavior.
This interface supports the following hooks.
- transformRequest
- configureDefaultValidations
- applyCustomValidations
- customiseMutationPayload
- handlePostOperation
note: The customiseGraphQLQuery is not applicable to DELETE, which is a write operation, so there is no read query to customize. This hook is declared on the read interface (ICommsGET), not on ICommsDELETE. To customize the soft-delete mutation payload, use customiseMutationPayload.
Account Delete Operation Use Cases
| Use Case | Hook(s) | Description | Example Scenarios | Benefit |
|---|---|---|---|---|
| Supply the Soft-Delete Status Field | customiseMutationPayload |
Adds the status field required to perform a soft delete. The hook can also include deletion metadata or other organization-specific fields in the GraphQL mutation payload. | - Set status to Deleted or Inactive<br>- Add a deletion timestamp <br>- Record the user who initiated the deletion <br>- Include custom deletion-reason fields |
Required to make the DELETE operation functional while retaining the Account for auditing, recovery, and historical reporting. |
| Prevent Deletion Under Business Rules | applyCustomValidations |
Applies custom business rules before the delete mutation is built. If a rule fails, the operation is stopped with an HTTP 422 response and a clear validation message. |
- Prevent deletion of an Account with active Contacts <br>- Block deletion when open Opportunities exist <br>- Restrict deletion to authorized roles <br>- Protect Accounts in locked lifecycle states | Blocks invalid or unauthorized deletion attempts early and gives clients a clear, actionable error message. |
| Resolve an External ID to an Account ID | transformRequest |
Converts a legacy or external identifier into the canonical Account ID expected by the delete operation and stores it in the shared request context as { id }. |
- Resolve a legacy customer number to an Account ID<br>- Map a partner-system key to { id }<br>- Convert an external billing reference into an Account ID<br>- Normalize identifiers from migrated systems |
Allows clients and legacy integrations to identify Accounts using familiar keys without changing the shared delete contract. |
| Add Custom Validation Flags | configureDefaultValidations |
Enables, disables, or adds validation flags for Account deletion according to organization-specific policies. This is especially important when the delete operation does not register built-in validations by default. | - Require Account-existence validation <br>- Enable concurrency or version checks <br>- Require confirmation for protected Accounts <br>- Apply stricter deletion checks for regulated organizations | Supports per-organization deletion policies without modifying the shared delete implementation. |
| Audit or Cascade After Deletion | handlePostOperation |
Runs after the delete mutation completes and receives the deleteResult summary. It can use the result to perform auditing, cascading updates, event publication, or other side effects. |
- Write an Account-deletion audit record <br>- Cascade the deleted status to related records <br>- Publish an Account-deleted event <br>- Invalidate related caches or search indexes <br>- Record deletion metrics | Enables reliable post-delete processing using the deleteResult summary while keeping side effects separate from the core operation. |
transformRequest
This hook transforms the request context before processing any operation. It is invoked early in the request lifecycle, allowing implementers to adjust the context for subsequent extensibility hooks.
Hook Method
Map<String, Object> transformRequest(Map<String, Object> context)
Sample Apex Implementation
Resolve an external ID to a Salesforce Contact ID.
global class OrganizationDeleteTransformRequestExt implements comms_apex_ext.IOrganizationPartyManagementDELETE {
global static Map<String, Object> transformRequest(Map<String, Object> context) {
if (context == null || !(context.get('id') instanceof String)) {
return context;
}
String idValue = (String) context.get('id');
if (idValue.length() != 15 && idValue.length() != 18) {
List<Account> matches = [
SELECT Id FROM Account WHERE External_Id__c = :idValue LIMIT 1
];
if (!matches.isEmpty()) {
context.put('id', matches[0].Id);
}
}
return context;
}
// customiseMutationPayload still REQUIRED — see HOOK 4 ...
}
configureDefaultValidations
This hook enables, disables, or modifies the built-in validation rules before they execute.
Hook Method
Map<String, Boolean> configureDefaultValidations(Map<String, Boolean> defaultValidationConfiguration, Map<String, Object> context)
Sample Apex Implementation
Add a custom flag consumed by applyCustomValidations.
global class OrganizationDeleteConfigValidationsExt implements comms_apex_ext.IOrganizationPartyManagementDELETE {
global static Map<String, Boolean> configureDefaultValidations(
Map<String, Boolean> defaultValidationConfiguration,
Map<String, Object> context
) {
Map<String, Boolean> overrides = defaultValidationConfiguration != null
? defaultValidationConfiguration.clone()
: new Map<String, Boolean>();
overrides.put('checkActiveContracts', true); // your own flag, read in applyCustomValidations
return overrides;
}
// customiseMutationPayload still REQUIRED — see HOOK 4 ...
}
applyCustomValidations
This hook validates custom business logic before retrieving customer record. If validation fails, it rejects the request and returns an error response.
The handler processes return values as follows.
Success:
- Return a map with validationStatus set to "pass" (case-insensitive).
- The API request continues normally.
- Other fields in the map are logged but not used.
Failure:
- Return a map with validationStatus set to "fail" (case-insensitive).
- The API request is terminated immediately.
- Raise a ValidationException containing
- message: value from validationMessage key (or "Validation failed" by default)
- details: value from validationDetails key (optional)
- The client receives an HTTP 400 error response.
Hook Method
Map<String, Object> applyCustomValidations(Map<String, Object> context)
Sample Apex Implementation
Prevent deletion when the Organization has child Accounts.
global class OrganizationDeletePreventExt implements comms_apex_ext.IOrganizationPartyManagementDELETE {
global static Map<String, Object> applyCustomValidations(Map<String, Object> context) {
Map<String, Object> result = new Map<String, Object>();
String organizationId = (String) context.get('id');
if (organizationId != null) {
Integer childAccounts = [
SELECT COUNT() FROM Account WHERE ParentId = :organizationId
];
if (childAccounts > 0) {
result.put('validationStatus', 'fail');
result.put('validationMessage',
'Cannot delete this Organization - deletion prevented by custom validation (it still has child Organizations)');
}
}
return result; // empty => proceed; validationStatus="fail" => HTTP 422
}
// customiseMutationPayload still REQUIRED — see HOOK 4 ...
}
customiseMutationPayload
This hook modifies the mutation payload before deleting a customer record. Use this to add deletion metadata, set soft-delete flags, or apply business logic transformations.
Hook Method
Map<String, Object> customiseMutationPayload(Map<String, Object> request, Map<String, Object> context)
Sample Apex Implementation
Supply the soft-delete status field.
global class OrganizationDeleteCustomMutationExt implements comms_apex_ext.IOrganizationPartyManagementDELETE {
global static Map<String, Object> customiseMutationPayload(
Map<String, Object> graphQLAsMap,
Map<String, Object> context
) {
Map<String, Object> node = new Map<String, Object>{
'path' => 'softDeleteOrganization',
'addFields' => new Map<String, Object>{
'Status__c' => 'Inactive',
'Deletion_Reason__c' => 'Deleted via TMF632 Organization API'
}
};
return new Map<String, Object>{
'nodes' => new List<Object>{ node }
};
}
// ... other hooks return null / empty map ...
}
handlePostOperation
This hook post-processes and transforms the API response after data retrieval.
Hook Method
Map<String, Object> handlePostOperation(Map<String, Object> graphQLQueryResultAsMap, Map<String, Object> constructedTMFResponse, Map<String, Object> context)
Sample Apex Implementation
Audit the deletion.
global class OrganizationDeleteHandlePostOpExt implements comms_apex_ext.IOrganizationPartyManagementDELETE {
global static Map<String, Object> handlePostOperation(
Map<String, Object> graphQLQueryResultAsMap,
Map<String, Object> constructedTMFResponse,
Map<String, Object> context
) {
Object dr = context != null ? context.get('deleteResult') : null;
if (dr instanceof Map<String, Object>) {
Map<String, Object> deleteResult = (Map<String, Object>) dr;
if (Boolean.TRUE.equals(deleteResult.get('success'))) {
insert new Organization_Deletion_Log__c(
Organization_Id__c = (String) deleteResult.get('deletedId'),
Deleted_By__c = UserInfo.getUserId()
);
}
}
return null; // no body for HTTP 204
}
// customiseMutationPayload still REQUIRED — see HOOK 4 ...
}
Full Implementation Example
Here's a complete sample Apex implementation using all supported hooks.
/**
* Complete TMF632 Organization (Party Management) DELETE API extension,
* demonstrating all hooks. customiseMutationPayload supplies the required soft-delete field.
*/
global class OrganizationPartyManagementDELETEExtension implements comms_apex_ext.IOrganizationPartyManagementDELETE {
// Hook 1: normalize / resolve the id.
global static Map<String, Object> transformRequest(Map<String, Object> context) {
return context;
}
// Hook 2: DELETE has no default validators; keep it that way.
global static Map<String, Boolean> configureDefaultValidations(
Map<String, Boolean> defaultValidationConfiguration,
Map<String, Object> context
) {
return new Map<String, Boolean>();
}
// Hook 3: block deletion when there are child Organizations.
global static Map<String, Object> applyCustomValidations(Map<String, Object> context) {
Map<String, Object> result = new Map<String, Object>();
String organizationId = (String) context.get('id');
if (organizationId != null) {
Integer childAccounts = [
SELECT COUNT() FROM Account WHERE ParentId = :organizationId
];
if (childAccounts > 0) {
result.put('validationStatus', 'fail');
result.put('validationMessage',
'Cannot delete this Organization - deletion prevented by custom validation (it still has child Organizations)');
}
}
return result;
}
// Hook 4 (REQUIRED): supply the soft-delete status field on the softDeleteOrganization node.
global static Map<String, Object> customiseMutationPayload(
Map<String, Object> graphQLAsMap,
Map<String, Object> context
) {
Map<String, Object> node = new Map<String, Object>{
'path' => 'softDeleteOrganization',
'addFields' => new Map<String, Object>{ 'Status__c' => 'Inactive' }
};
return new Map<String, Object>{ 'nodes' => new List<Object>{ node } };
}
// Hook 5: audit the deletion (no response body).
global static Map<String, Object> handlePostOperation(
Map<String, Object> graphQLQueryResultAsMap,
Map<String, Object> constructedTMFResponse,
Map<String, Object> context
) {
Object dr = context != null ? context.get('deleteResult') : null;
if (dr instanceof Map<String, Object>
&& Boolean.TRUE.equals(((Map<String, Object>) dr).get('success'))) {
// audit / downstream cleanup (e.g. re-parent child Accounts, remove AAR records)
}
return null;
}
}