The ITroubleTicketManagementPATCH interface supports extensibility for PATCH operations by allowing validation, transformation, and post-processing of update requests. Implementations can enforce business rules, adjust mutation payloads, and refine the resulting responses maintaining TMF-compliant behavior.
Following hook is not used for the Trouble Ticket Management API. If implemented, the method may be invoked, but its return values are ignored.
configureDefaultValidations
Note
Update Lifecycle Use Cases and Hook Mapping
The following table lists common use cases and hooks required for PATCH operation.
Use Case
Hook(s)
Description
Example Scenarios
Benefit
Enforce Status Transitions
applyCustomValidations
Validates requested status changes before updating the record to ensure transitions adhere to defined lifecycle rules, regulatory constraints, or business policies. Stops invalid or unauthorized state changes.
• Prevent transition from Inactive → Active without required approvals• Block changes to Suspended unless preconditions are met• Enforce linear lifecycle progression (e.g., Pending → Active, but not Closed → Active)
Prevents invalid or noncompliant state transitions and preserves data integrity
Automatic Field Population
customiseMutationPayload
Automatically populate fields like Reason or Origin during updates.
• Add Reason and Origin fields• Track system-initiated vs. user-initiated changes
Provides a complete and reliable audit trail for internal governance and external compliance needs
Validate Data Format
applyCustomValidations
Ensures updated data—such as contact details, identifiers, or structured fields—meets required formatting rules before the update is processed. Prevents malformed or inconsistent data from entering the system.
• Validate phone number format• Confirm email structure and domain correctness• Ensure address fields follow standardized formats
Ensures required fields are always set without requiring client to provide them
Response Enrichment
handlePostOperation
Automatically enriches the update payload with audit metadata before persistence. Ensures all modifications are traceable and compliant with auditing standards.
• Add “modifiedBy” and timestamp fields• Track system-initiated vs. user-initiated changes• Add audit IDs for downstream monitoring systems
Provides a complete and reliable audit trail for internal governance and external compliance needs
CaseNumber to Id Resolution
transformRequest
Resolve CaseNumber identifiers to Salesforce Ids for API compatibility.
• An external system sends a CaseNumber (e.g., 00001027), which is resolved to a Salesforce record ID for API processing
Support external systems that use CaseNumber instead of Salesforce Id
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.
1public Map<String, Object> transformRequest(Map<String, Object> context) {2 if (context == null) {3 return context;4 }56 Object idObj = context.get('id');7 if (idObj == null || !(idObj instanceof String)) {8 return context;9 }1011 String idValue = (String)idObj;1213 // Check if the ID looks like a Salesforce ID (starts with 500, 00X, etc.)14 // If not, assume it's a CaseNumber and resolve it15 if (idValue.length() == 15 || idValue.length() == 18) {16 // Looks like a Salesforce ID, return context as-is17 return context;18 }1920 // Query Case objects where CaseNumber matches the provided ID21 List<Case> cases = [22 SELECT Id, CaseNumber23 FROM Case24 WHERE CaseNumber = :idValue25 LIMIT 126 ];2728 // If found, replace the ID in context with the Salesforce ID29 if (!cases.isEmpty() && cases[0].CaseNumber != null) {30 context.put('id', cases[0].Id);31 }3233 return context;34}
applyCustomValidations
This hook validates custom business logic before updating a customer data. If validation fails, rejects the request and returns an error response.
The handler processes return values as follows.
Success:
Return a map with validationStatus set to any value other than “fail” (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)
1public Map<String, Object> applyCustomValidations(Map<String, Object> context) {2 // Input context:3 // {4 // api: 'TroubleTicketManagement',5 // version: '5.0',6 // id: '00001027',7 // requestBody: {8 // status: 'Closed',9 // name: 'Updated Name'10 // }11 // }1213 String troubleTicketId = (String) context.get('id');14 Map<String, Object> requestBody = (Map<String, Object>) context.get('requestBody');1516 if (requestBody == null || !requestBody.containsKey('status')) {17 // No status update requested, validation passes18 return null;19 }2021 String newStatus = (String) requestBody.get('status');2223 Map<String, Object> validationResult = new Map<String, Object>();2425 try {26 // Fetch current trouble ticket status27 Case troubleTicket = [SELECT Id, Status, CaseNumber FROM Case WHERE CaseNumber = :troubleTicketId LIMIT 1];28 String currentStatus = troubleTicket.Status;2930 // Validate status transition: Cannot change from Closed to any other status31 if ('Closed'.equals(currentStatus) && !'Closed'.equals(newStatus)) {32 validationResult.put('validationStatus', 'FAIL');33 validationResult.put('validationMessage', 'Cannot change status from Closed to ' + newStatus);34 validationResult.put('validationDetails', new Map<String, Object>{35 'denialReason' => 'INVALID_STATUS_TRANSITION',36 'currentStatus' => currentStatus,37 'requestedStatus' => newStatus38 });39 } else {40 // Validation passes41 validationResult.put('validationStatus', 'PASS');42 validationResult.put('validationMessage', 'Status transition is valid');43 }44 } catch (Exception e) {45 // FAIL: Error during validation46 validationResult.put('validationStatus', 'FAIL');47 validationResult.put('validationMessage', 'Validation error: ' + e.getMessage());48 validationResult.put('validationDetails', new Map<String, Object>{49 'errorType' => e.getTypeName()50 });51 }5253 return validationResult;54}
customiseMutationPayload
This hook modifies the mutation payload before updating a customer record. Use this to add computed fields, transform values, or apply business logic transformations.
1public Map<String, Object> customiseMutationPayload(2 Map<String, Object> mutationGraphQLPayload,3 Map<String, Object> context4) {5 // Create mutation transformation specification6 List<Map<String, Object>> transformationNodes = new List<Map<String, Object>>();78 // Node 1: Add custom input fields to the Case mutation9 // Path: troubleTicket (the Case mutation alias)10 Map<String, Object> modifyInputNode = new Map<String, Object>{11 'path' => 'troubleTicket',12 'modifyInput' => new Map<String, Object>{13 'addInputFields' => new Map<String, Object>{14 'Reason' => 'Updated via PATCH API',15 'Origin' => 'Web'16 }17 }18 };19 transformationNodes.add(modifyInputNode);2021 // Return transformation specification22 return new Map<String, Object>{23 'nodes' => transformationNodes24 };25}
For Trouble Ticket Management API, use path troubleTicket to target the main Case mutation
Note
customiseGraphQLQuery
This hook modifies the GraphQL query before execution to add fields, filters, or transformations. Returns a map with a spec key containing a list of QueryTransformationNode objects.