Skip to content

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: afterUpdate only
  • 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 (Map) - Map of Order IDs to new Order records - oldRecordsMap (Map) - Map of Order IDs to old Order records

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 by CanceledOrderLogic
  • 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

  1. Trigger Handler Pattern: Extends TriggerHandler for consistent trigger management
  2. Separation of Concerns: Delegates business logic to dedicated service class
  3. Single Responsibility: Handler only routes events, doesn't implement logic
  4. 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

  1. Bulkification: Handler supports bulk operations (processes all records in trigger context)
  2. Single Trigger: Ensure only one trigger per object (enforced by framework)
  3. Recursive Prevention: TriggerHandler base class should provide recursion control
  4. Error Handling: Add try-catch for graceful failure handling

Error Handling

Exception Types Thrown

  • None directly - Exceptions from CanceledOrderLogic bubble 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

  1. No Exception Logging: Failures not logged for debugging
  2. No Graceful Degradation: Single order failure fails entire batch
  3. No Partial Success: All-or-nothing transaction (DML context)
  4. No User-Friendly Messages: Technical exceptions exposed to end users
// 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 sharing is 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

  1. Field-Level Security: Validate FLS in CanceledOrderLogic if needed
  2. Audit Trail: Order updates automatically create Field History records
  3. 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 CanceledOrderLogic executed 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 CanceledOrderLogic may 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 afterUpdate signature breaks TriggerHandler contract
  • Changing delegation call affects CanceledOrderLogic integration
  • Adding filtering logic may change which orders are processed
  • 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