Skip to content

Trigger Name: SubscriptionTrigger

Last Updated: 2025-10-22 Source Code: https://github.com/AANP-IT/I2C.Salesforce.Metadata/blob/STAGING/force-app/main/default/triggers/SubscriptionTrigger.trigger

API Name: SubscriptionTrigger Object: Subscription__c (Custom Object) Pattern: Handler Pattern with Switch Statement

Business Purpose

This trigger manages Subscription__c lifecycle events to synchronize community memberships with Higher Logic. When subscriptions for community products are created or updated, it automatically enqueues async jobs to update the Account.Higher_Logic_Communities__c field, ensuring community access is properly provisioned in the external Higher Logic platform.

Trigger Events

This trigger fires on the following events: - ☐ Before Insert - ☐ Before Update - ☐ Before Delete - ☑️ After Insert - ☑️ After Update - ☐ After Delete - ☐ After Undelete

Trigger Handler

Handler Class: SubscriptionTriggerHandler.cls Pattern: Handler with Static Methods and Switch Statement Entry Point: Switch statement calls static handler method

trigger SubscriptionTrigger on Subscription__c (
    after insert, after update
) {
    switch on Trigger.operationType{
        when AFTER_Insert,AFTER_Update {
            SubscriptionTriggerHandler.syncCommunities(Trigger.newMap);
        }
    }
}

Process Flow by Event

After Insert

Purpose: Sync new subscriptions to Higher Logic communities

Business Logic: 1. Check if handler already ran (recursion prevention) 2. Create I2C_QueueableCommunitiesSync with subscription records 3. Enqueue Queueable job to sync communities asynchronously

Methods Called: - SubscriptionTriggerHandler.syncCommunities(Map<Id, Subscription__c> subscriptionNewMap) - I2C_QueueableCommunitiesSync (Queueable class)


After Update

Purpose: Sync subscription updates to Higher Logic communities

Business Logic: 1. Same process as After Insert 2. Queueable job processes subscription changes 3. Updates Account.Higher_Logic_Communities__c field

Methods Called: - SubscriptionTriggerHandler.syncCommunities(Map<Id, Subscription__c> subscriptionNewMap) - I2C_QueueableCommunitiesSync (Queueable class)


Key Business Rules

Validation Rules

  • Only processes subscriptions for community products (Family = 'Communities')
  • Subscription Product2 Name added to Account.Higher_Logic_Communities__c
  • Multiple communities stored as semicolon-separated list

Field Updates

  • Account.Higher_Logic_Communities__c: Semicolon-separated list of community names
  • Account.HL__c: Boolean flag set to true if communities exist
  • Account records updated with community memberships
  • Higher Logic platform provisioned with community access (external)

Bulkification & Governor Limits

Bulkified: Partial Max Records Handled: Limited by Queueable job limits SOQL Queries: 2 in handler (Product2 and Account queries) DML Operations: 1 in handler (Account update)

Bulkification Strategy

  • Trigger passes all subscriptions to handler as map
  • Handler enqueues single Queueable job
  • Queueable processes subscriptions in bulk
  • Queries Product2 and Account records in bulk
  • Single DML to update Accounts

Governor Limit Considerations

  • Queueable Limit: 1 Queueable job per trigger execution
  • SOQL: 2 queries (Product2, Account)
  • DML: 1 DML statement (Account update)
  • Recursion: Static boolean prevents re-execution

Recursion Prevention

Strategy: Static boolean flag in handler class

Implementation:

public static Boolean alreadyRan = false;

public static void syncCommunities(Map<Id, Subscription__c> subscriptionNewMap){
    if(!alreadyRan){
        alreadyRan = true;
        I2C_QueueableCommunitiesSync q = new I2C_QueueableCommunitiesSync(subscriptionNewMap);
        System.enqueueJob(q);
    }
}

Scenarios: - Prevents re-execution within same transaction - Does not prevent cross-transaction recursion - Queueable runs in separate transaction (avoids same-transaction recursion)

Execution Order & Dependencies

Order of Execution Impact

  • After Insert/Update: Runs after validation rules
  • Queueable execution happens asynchronously after transaction commits

Dependent Triggers

  • AccountTrigger: Could be impacted by Account updates
  • Risk: AccountTrigger might update Accounts, creating potential circular dependency

Dependent Processes

  • I2C_QueueableCommunitiesSync: Async community sync logic
  • Higher Logic Integration: External platform for community access
  • Account community provisioning

Error Handling

Strategy: Static boolean flag prevents errors from recursion

User Experience: - Success: Subscription saves, communities synced asynchronously - Validation Error: Standard Salesforce errors - System Error: Full transaction rollback, Queueable not enqueued

Logging: - Logging likely in I2C_QueueableCommunitiesSync - No explicit logging in trigger/handler

Rollback Behavior: - Subscription save rollback on errors - Queueable job not enqueued if transaction fails - Queueable failures don't rollback subscription

Dependencies

Apex Classes

  • SubscriptionTriggerHandler: Handler with static methods
  • I2C_QueueableCommunitiesSync: Queueable job for community sync
  • SubscriptionTriggerHandler.updateAccountCommunities: Helper method

Salesforce Objects

  • Subscription__c: Custom object (primary)
  • Account: Standard object (updated)
  • Product2: Standard object (queried for community names)

Custom Settings/Metadata

  • None visible

External Systems

  • Higher Logic: Community management platform

Testing

Test Class: SubscriptionTriggerHandlerTest.cls (likely) Coverage: Unknown

Test Scenarios: - Single subscription insert for community product - Bulk subscription insert (200 records) - Subscription update - Non-community product subscriptions (should be skipped) - Multiple subscriptions per Account - Queueable job execution - Recursion prevention

Performance Considerations

Average Execution Time: Fast (enqueues Queueable) Max Records Processed: Queueable limit of 50 per transaction (org-wide) Async Processing: Yes - Queueable for community sync

Optimization Opportunities: - Already optimized with Queueable pattern - Monitor Queueable job limits in high-volume scenarios - Consider Platform Events for complete decoupling

Changes & History

  • Author: Original implementation (team maintained)
  • Pattern: Hybrid switch statement with handler static methods

Pre-Go-Live Concerns

CRITICAL - Fix Before Go-Live

  • Queueable Limit Risk: Only 50 Queueable jobs per transaction org-wide. High subscription volume could hit limits
  • No Error Handling: No try-catch around Queueable enqueue
  • Recursion Risk: Static boolean only prevents same-transaction recursion

HIGH - Address Soon After Go-Live

  • No Logging: No audit trail of community sync operations
  • Hard-coded Product Family: 'Communities' product family hard-coded in handler
  • Higher Logic Failure Handling: No retry if Higher Logic integration fails
  • Account Update Recursion: AccountTrigger could update Subscription__c creating circular dependency

MEDIUM - Future Enhancement

  • Trigger Settings: Custom metadata to enable/disable trigger
  • Event-Driven Architecture: Consider Platform Events instead of Queueable
  • Better Error Messages: User-friendly messages for sync failures
  • Community Sync Status: Track sync status on Subscription records

LOW - Monitor

  • Queueable Job Queue: Monitor Queueable job execution times
  • Higher Logic API Performance: Track external API response times
  • Account Field Length: Monitor Higher_Logic_Communities__c doesn't exceed field length

Maintenance Notes

Complexity: Medium Recommended Review Schedule: Quarterly

Key Maintainer Notes: - This trigger uses Queueable for async Higher Logic integration - Static boolean prevents same-transaction recursion only - Handler method is static (no instance state) - I2C_QueueableCommunitiesSync contains actual sync logic - Queueable jobs have org-wide limit of 50 per transaction - Always test with bulk operations and Queueable job monitoring - Higher Logic integration may have its own rate limits

Deactivation Instructions: Add custom metadata check in trigger:

trigger SubscriptionTrigger on Subscription__c (after insert, after update) {
    if (TriggerSettings__mdt.getInstance('Subscription')?.Disabled__c == true) {
        return;
    }
    switch on Trigger.operationType{
        when AFTER_Insert,AFTER_Update {
            SubscriptionTriggerHandler.syncCommunities(Trigger.newMap);
        }
    }
}

Higher Logic Integration Notes: - External platform for community management - API credentials/configuration likely in Custom Metadata or Named Credentials - Test integration thoroughly in sandbox - Document Higher Logic API error codes and handling - Monitor API limits and quotas