IAccountManagementDELETE Apex Interface

The IAccountManagementDELETE 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.

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
Resolve an External Key to the Salesforce ID transformRequest Resolves a caller-provided business key or external identifier to the canonical Salesforce Account ID before validation and deletion processing begins. - Resolve an ERP customer number <br>- Map a billing-system identifier to an Account ID<br>- Translate a partner-specific key <br>- Resolve a legacy account reference Allows callers to address Account records using their own identifiers instead of requiring a Salesforce ID.
Block Deletion Based on Business Preconditions applyCustomValidations Evaluates business rules and dependent-record conditions before the delete mutation is built. The operation is rejected when the Account does not satisfy the required deletion criteria. - Prevent deletion when active subscriptions exist <br>- Block deletion when the Account has an open balance <br>- Reject deletion when active contracts or orders exist <br>- Protect Accounts involved in unresolved disputes Prevents invalid deletion or deactivation of Accounts that still have active financial, contractual, or operational obligations.
Capture a Deactivation Reason or Audit Field customiseMutationPayload (addFields) Adds organization-specific fields to the mutation payload without replacing the standard delete input. These fields can capture the reason, actor, source, or timestamp associated with the deactivation. - Store a deactivation reason code <br>- Record the user who initiated the operation <br>- Add a deactivation timestamp <br>- Capture the originating channel or system Records why and how the Account was deactivated, improving traceability and operational reporting.
Override the Terminal Status customiseMutationPayload (modifyInput) Modifies the standard mutation input to use an organization-specific terminal status instead of the default soft-delete status. - Set the status to Cancelled<br>- Use Closed for completed Account relationships<br>- Apply a region-specific terminal state <br>- Select a status based on Account type Aligns soft-delete behavior with organization-specific lifecycle models by using Cancelled, Closed, or another terminal status instead of Inactive.
Cascade Cleanup or Deprovisioning handlePostOperation Runs after the Account mutation completes and uses the operation result to clean up related resources or initiate downstream deprovisioning. - Deactivate Account-contact junctions <br>- Revoke associated entitlements <br>- Disable downstream access or services <br>- Publish a deprovisioning event<br>- Notify billing or subscription systems Keeps related records and downstream systems consistent with the Account's deactivated state.
Create an Audit Trail handlePostOperation Records the completed deletion or deactivation in an audit or compliance system after the mutation succeeds. - Write a compliance audit entry <br>- Record the actor, timestamp, and affected Account <br>- Store the mutation result and deactivation reason <br>- Publish an immutable deletion event Provides a reliable compliance record of Account deletions and deactivations.

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 AccountMgmtTransformRequestDeleteExt implements comms_apex_ext.IAccountManagementDELETE {


    global static Map<String, Object> transformRequest(Map<String, Object> context) {
        if (context == null) {
            return context;
        }


        // If the caller addressed the record by an external key, resolve it to the SF id.
        Object idObj = context.get('id');
        if (idObj instanceof String && ((String) idObj).startsWith('EXT-')) {
            String externalKey = (String) idObj;
            List<BillingAccount> matches = [
                SELECT Id FROM BillingAccount WHERE ExtlBillingAccountId__c = :externalKey LIMIT 1
            ];
            if (!matches.isEmpty()) {
                context.put('id', matches[0].Id);
            }
        }
        return context;
    }


    // ... other hooks return null / empty map ...
}

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

Block deletion when the Account has active subscriptions.

global class AccountMgmtCustomValidationDeleteExt implements comms_apex_ext.IAccountManagementDELETE {


    global static Map<String, Object> applyCustomValidations(Map<String, Object> context) {
        Map<String, Object> result = new Map<String, Object>();
        String billingAccountId = (String) context.get('id');


        if (billingAccountId != null) {
            Integer activeCount = [
                SELECT COUNT() FROM Order
                WHERE BillingAccountId = :billingAccountId AND Status = 'Activated'
            ];
            if (activeCount > 0) {
                result.put('validationStatus', 'fail');
                result.put('validationMessage',
                    'Cannot delete a billing account with active subscriptions.');
                result.put('validationDetails', new Map<String, Object>{
                    'billingAccountId'    => billingAccountId,
                    'activeSubscriptions' => activeCount,
                    'rule'                => 'NO_DELETE_WITH_ACTIVE_SUBS'
                });
                return result;
            }
        }


        result.put('validationStatus', 'pass');
        return result;
    }
    // ... other hooks return null / empty map ...
}

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

Add a custom field alongside the Status = Inactive change so the soft delete captures why the account was deactivated.

global class AccountMgmtMutationPayloadDeleteExt implements comms_apex_ext.IAccountManagementDELETE {


    global static Map<String, Object> customiseMutationPayload(
        Map<String, Object> mutationGraphQLPayload,
        Map<String, Object> context
    ) {
        Map<String, Object> node = new Map<String, Object>{
            'path'      => 'softDeleteBillingAccount',
            'addFields' => new Map<String, Object>{
                'ExtlDeactivationReason__c' => 'Deleted via TMF666 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-log the soft delete and cascade cleanup.

global class IndividualDeleteHandlePostOpExt implements comms_apex_ext.IIndividualPartyManagementDELETE {


    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 Individual_Deletion_Log__c(
                    Individual_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.

global class AccountMgmtPostOpAuditDeleteExt implements comms_apex_ext.IAccountManagementDELETE {


    global static Map<String, Object> handlePostOperation(
        Map<String, Object> graphQLResult,
        Map<String, Object> deleteResult,
        Map<String, Object> context
    ) {
        try {
            Boolean success = deleteResult != null
                && Boolean.TRUE.equals(deleteResult.get('success'));
            String deletedId = deleteResult != null
                ? (String) deleteResult.get('deletedId')
                : (String) context.get('id');


            System.debug('BillingAccount soft-deleted via TMF666 DELETE by '
                + UserInfo.getName() + ': ' + deletedId + ' (success=' + success + ')');


            // Example cascade: mark related junction records inactive (bulk-safe single DML).
            if (success && deletedId != null) {
                // ... enqueue or perform cleanup keyed on deletedId ...
            }
        } catch (Exception e) {
            System.debug('Post-delete handling failed: ' + e.getMessage());
        }
        // Return value is ignored for DELETE.
        return null;
    }


    // ... other hooks return null / empty map ...
}