Class Name: OrderTriggerHandler¶
Last Updated: 2025-10-22 Source Code: https://github.com/AANP-IT/I2C.Salesforce.Metadata/blob/STAGING/force-app/main/default/classes/OrderTriggerHandler.cls
API Name: OrderTriggerHandler Type: Trigger Handler Test Coverage: GeolocationServiceTest, SObjectTriggerHandlerTest
Business Purpose¶
The OrderTriggerHandler class manages Order object trigger logic, specifically handling order cancellations through the trigger framework. This handler:
- Routes Order update events to cancellation processing logic
- Maintains separation between trigger infrastructure and business logic
- Supports automated order management workflows when orders are cancelled
Class Overview¶
- Author: Ryan O'Sullivan
- Created: 2025-01-22
- Test Classes: GeolocationServiceTest, SObjectTriggerHandlerTest
- Scope/Sharing:
with sharing- Respects record-level security - Extends:
TriggerHandler- Base trigger framework class - Supported Events:
afterUpdateonly - Key Responsibilities:
- Receive Order update notifications
- Route cancelled orders to
CanceledOrderLogic - Maintain clean trigger architecture
Public Methods¶
afterUpdate¶
override protected void afterUpdate(Map<Id, SObject> updatedRecordsMap, Map<Id, SObject> oldRecordsMap)
Purpose: Handles Order after update events, delegating to cancellation logic for cancelled orders.
Parameters:
- updatedRecordsMap (MapoldRecordsMap (Map
Returns: void
Business Logic:
1. Event Reception (line 9): Receives updated and old Order maps from trigger
2. Delegation (line 10): Passes both maps to CanceledOrderLogic.run() for processing
Implementation:
override protected void afterUpdate(Map<Id, SObject> updatedRecordsMap, Map<Id, SObject> oldRecordsMap) {
CanceledOrderLogic.run(updatedRecordsMap, oldRecordsMap);
}
Issues/Concerns:
- ⚠️ No Filtering: Passes ALL updated orders regardless of Status change
- CanceledOrderLogic must filter to only cancelled orders
- Inefficient if most updates aren't cancellations
- ⚠️ No Null Check: Doesn't verify maps are non-null
- ⚠️ No Error Handling: No try-catch around delegation
- ⚠️ Generic Processing: Doesn't check if Status field actually changed
- ✅ Clean Separation: Delegates to business logic class
- ✅ Old Values Available: Passes old map for field change detection
Trigger Context:
Order Status: 'Activated' → 'Cancelled'
↓
OrderTrigger fires (afterUpdate)
↓
OrderTriggerHandler.afterUpdate() receives maps
↓
CanceledOrderLogic.run() processes cancellation
↓
Business logic executes (refunds, notifications, etc.)
Recommended Improvements:
override protected void afterUpdate(Map<Id, SObject> updatedRecordsMap, Map<Id, SObject> oldRecordsMap) {
if (updatedRecordsMap == null || updatedRecordsMap.isEmpty()) {
return;
}
// Filter to only orders where Status changed to 'Canceled'
Map<Id, SObject> cancelledOrders = new Map<Id, SObject>();
for (Id orderId : updatedRecordsMap.keySet()) {
Order newOrder = (Order)updatedRecordsMap.get(orderId);
Order oldOrder = (Order)oldRecordsMap.get(orderId);
if (newOrder.Status == 'Canceled' && oldOrder.Status != 'Canceled') {
cancelledOrders.put(orderId, newOrder);
}
}
if (!cancelledOrders.isEmpty()) {
try {
CanceledOrderLogic.run(cancelledOrders, oldRecordsMap);
} catch (Exception e) {
System.debug(LoggingLevel.ERROR, 'Error processing cancelled orders: ' + e.getMessage());
// Consider whether to re-throw or log silently
}
}
}
Trigger Context¶
Supported Operations¶
- beforeInsert: ❌ Not implemented
- afterInsert: ❌ Not implemented
- beforeUpdate: ❌ Not implemented
- afterUpdate: ✅ Implemented (line 9)
- beforeDelete: ❌ Not implemented
- afterDelete: ❌ Not implemented
- afterUndelete: ❌ Not implemented
Why Only afterUpdate?¶
This handler focuses exclusively on afterUpdate because:
- Cancellation Workflow: Orders are created then later cancelled (update operation)
- Status Changes: Cancellation involves Status field changes from Active → Cancelled
- Post-Commit Processing: Cancellation logic (refunds, notifications) should run after DML commits
- No Insert Logic: New orders don't need cancellation processing
Dependencies¶
Salesforce Objects¶
- Order (Standard Object)
- Fields:
Id,Status, and potentially others accessed byCanceledOrderLogic - Trigger: This handler processes Order updates
Custom Settings/Metadata¶
- None directly (may be used by
CanceledOrderLogic)
Other Classes¶
- TriggerHandler (Base Class):
- Framework for trigger orchestration
- Provides
afterUpdate()override method - Manages trigger context
- CanceledOrderLogic:
- Business logic for order cancellations
- Processes cancelled Order records
- Likely handles refunds, notifications, inventory updates
- OrderItemSummaryTriggerHandler:
- Related handler for OrderItemSummary change events
- Also delegates to
CanceledOrderLogic
External Services¶
- None directly (may be invoked by
CanceledOrderLogic)
Design Patterns¶
- Trigger Handler Pattern: Extends
TriggerHandlerfor consistent trigger management - Separation of Concerns: Delegates business logic to dedicated service class
- Single Responsibility: Handler only routes events, doesn't implement logic
- Template Method Pattern: Overrides specific trigger context methods from base class
Governor Limits Considerations¶
Current Impact (Per Trigger Execution)¶
- SOQL Queries: 0 (delegated to CanceledOrderLogic)
- DML Statements: 0 (delegated to CanceledOrderLogic)
- CPU Time: Minimal (map passing only)
- Heap Size: Minimal (map reference passed)
Scalability Analysis¶
- ✅ Efficient Delegation: Only passes map references (no data copying)
- ⚠️ Bulk Processing: Handler must process all updates in bulk efficiently
- ⚠️ No Filtering: Passes all orders even if not cancelled (inefficient)
- ⚠️ CanceledOrderLogic Dependency: Scalability depends on business logic implementation
Trigger Best Practices¶
- Bulkification: Handler supports bulk operations (processes all records in trigger context)
- Single Trigger: Ensure only one trigger per object (enforced by framework)
- Recursive Prevention: TriggerHandler base class should provide recursion control
- Error Handling: Add try-catch for graceful failure handling
Error Handling¶
Exception Types Thrown¶
- None directly - Exceptions from
CanceledOrderLogicbubble up to trigger
Exception Types Caught¶
- None - No try-catch blocks
Error Handling Strategy¶
- No Local Handling: Exceptions propagate to trigger context
- Trigger Rollback: Uncaught exceptions roll back entire trigger transaction
- User Experience: Errors displayed to user as trigger exception messages
Error Handling Gaps¶
- No Exception Logging: Failures not logged for debugging
- No Graceful Degradation: Single order failure fails entire batch
- No Partial Success: All-or-nothing transaction (DML context)
- No User-Friendly Messages: Technical exceptions exposed to end users
Recommended Monitoring¶
// Query failed trigger executions
SELECT Id, ApexClass, Message, StackTrace, RequestId
FROM ApexLog
WHERE ApexClass = 'OrderTriggerHandler'
AND Operation LIKE '%TRIGGER%'
AND Status = 'FAILED'
AND CreatedDate = TODAY
// Monitor trigger performance
SELECT Id, DurationMilliseconds, CpuTime, RunTime
FROM ApexLog
WHERE ApexClass = 'OrderTriggerHandler'
AND CreatedDate = LAST_N_DAYS:7
ORDER BY DurationMilliseconds DESC
Security Considerations¶
Sharing Model¶
- WITH SHARING: Respects record-level security
- Implication: Trigger runs in user context with their permissions
- System Context: Most triggers run in system mode (ignore sharing by default)
with sharingis redundant in trigger context but good practice
Data Access¶
- Order Records: User must have edit access to update orders
- Cancellation Logic: Downstream logic may require additional permissions
- Audit Trail: Order Status changes tracked in Field History
Best Practices¶
- Field-Level Security: Validate FLS in
CanceledOrderLogicif needed - Audit Trail: Order updates automatically create Field History records
- Bypass Sharing: Consider if cancellation logic should run in system mode
Test Class Requirements¶
Required Test Coverage¶
@IsTest
public class OrderTriggerHandlerTest {
@TestSetup
static void setup() {
// Create test account
Account acc = new Account(Name = 'Test Account');
insert acc;
// Create test order
Order ord = new Order(
AccountId = acc.Id,
EffectiveDate = Date.today(),
Status = 'Draft',
TotalAmount = 100.00
);
insert ord;
// Activate order
ord.Status = 'Activated';
update ord;
}
@IsTest
static void testAfterUpdate_OrderCancelled() {
Order ord = [SELECT Id, Status FROM Order LIMIT 1];
Assert.areEqual('Activated', ord.Status, 'Order should start as Activated');
Test.startTest();
// Cancel order
ord.Status = 'Canceled';
update ord;
Test.stopTest();
// Verify CanceledOrderLogic was called
// This requires observable side effects from CanceledOrderLogic
// E.g., refund orders created, status updates, etc.
}
@IsTest
static void testAfterUpdate_BulkCancellation() {
// Create multiple orders
List<Order> orders = new List<Order>();
Account acc = [SELECT Id FROM Account LIMIT 1];
for (Integer i = 0; i < 200; i++) {
orders.add(new Order(
AccountId = acc.Id,
EffectiveDate = Date.today(),
Status = 'Activated',
TotalAmount = 100.00
));
}
insert orders;
Test.startTest();
// Bulk cancel orders
for (Order ord : orders) {
ord.Status = 'Canceled';
}
update orders;
Test.stopTest();
// Verify bulk processing
// Check that all orders were processed correctly
}
@IsTest
static void testAfterUpdate_NonCancellationUpdate() {
Order ord = [SELECT Id, Status, TotalAmount FROM Order LIMIT 1];
Test.startTest();
// Update non-status field
ord.TotalAmount = 200.00;
update ord;
Test.stopTest();
// Should not trigger cancellation logic
// Verify no side effects from CanceledOrderLogic
}
@IsTest
static void testTriggerHandler_OnlyAfterUpdateSupported() {
// Verify no other trigger contexts are implemented
OrderTriggerHandler handler = new OrderTriggerHandler();
// Only afterUpdate should be overridden
// Other contexts should use base class (no-op)
}
}
Test Data Requirements¶
- Account: Standard account for order association
- Order: Orders with various statuses
- CanceledOrderLogic Dependencies: Any objects/data that logic requires
Code Coverage Notes¶
- Target: 100% (only 5 lines, very simple class)
- Key Scenarios: Order cancellation (status change to 'Canceled')
- Bulk Testing: Verify bulk operations (200 orders)
- Observable Effects: Test must verify
CanceledOrderLogicexecuted correctly
Changes & History¶
| Date | Author | Description |
|---|---|---|
| 2025-01-22 | Ryan O'Sullivan | Initial implementation for Order cancellation handling |
| (Current) | - | Documentation added |
Pre-Go-Live Concerns¶
CRITICAL¶
- None - Class is straightforward with minimal risk
HIGH¶
- No Filtering: Processes ALL Order updates, not just cancellations
- Add filtering for Status = 'Canceled' before delegating
- Improves performance by reducing unnecessary processing
- No Error Handling: Uncaught exceptions fail entire trigger transaction
- Add try-catch with error logging
- Consider partial success pattern if appropriate
MEDIUM¶
- No Null Checks: Doesn't validate input maps
- Add null/empty checks for defensive programming
- No Status Change Detection: Doesn't verify Status actually changed
- Filter to only orders where Status changed to 'Canceled'
LOW¶
- Minimal Documentation: No javadoc comments
- Add method-level documentation
- Test Coverage: Integration with
CanceledOrderLogicmay need verification
Maintenance Notes¶
📋 Monitoring Recommendations¶
- Trigger Performance: Monitor execution time and governor limits
- Cancellation Volume: Track number of orders cancelled
- Error Rate: Alert on trigger failures
- Field Changes: Monitor which Status transitions trigger cancellations
🔧 Debugging Tips¶
// View trigger debug logs
SELECT Id, Operation, Status, DurationMilliseconds, Request
FROM ApexLog
WHERE ApexClass = 'OrderTriggerHandler'
AND CreatedDate = TODAY
ORDER BY StartTime DESC
LIMIT 100
// Query recent order cancellations
SELECT Id, OrderNumber, Status, LastModifiedDate
FROM Order
WHERE Status = 'Canceled'
AND LastModifiedDate = TODAY
ORDER BY LastModifiedDate DESC
⚠️ Breaking Change Risks¶
- Modifying
afterUpdatesignature breaksTriggerHandlercontract - Changing delegation call affects
CanceledOrderLogicintegration - Adding filtering logic may change which orders are processed
🔗 Related Components¶
- TriggerHandler: Base trigger framework class
- CanceledOrderLogic: Business logic for order cancellations
- OrderItemSummaryTriggerHandler: Related handler for order item events
- Order Object: Source object for trigger events
- Order Management Flows: Cancellation and refund workflows
Business Owner¶
Primary Contact: Order Management Team Technical Owner: Ryan O'Sullivan / Salesforce Development Team Created: 2025-01-22 Last Reviewed: [Date]
Documentation Status: ✅ Complete Code Review Status: ⚠️ Recommend adding filtering and error handling Test Coverage: Target 100% (simple class) Test Classes: GeolocationServiceTest, SObjectTriggerHandlerTest