BuildCommunicationScopeForRecord

What It Does

When a user opens the CallCore timeline on a record page, the package needs to know which CRM records are "in scope" — that is, which records should be checked for matching phone numbers when retrieving call history.

By default:

  • Contact page — the Contact itself plus its parent Account.
  • Account page — the Account plus all its Contacts.
  • Opportunity page — the Opportunity plus its Account (delegating to the Account scope logic).
  • Any other record — the anchor record only.

Implement BuildCommunicationScopeForRecord.IStrategy to replace this logic for a specific object type or to add support for a custom object.

Interface

global interface IStrategy {
    void build(Context context);
}

Context

Input

Field Type Description
anchorRef callcoreio.RecordRef The record the timeline is being viewed from. Provides recordId and sObjectType.

Write Methods

Call these from your build implementation to add records to the scope:

Method Description
addToScope(Id id) Adds a single record ID to scope. Null-safe.
addToScope(Iterable<Id> ids) Adds multiple record IDs. Null-safe.
addToScope(callcoreio.RecordRef recordRef) Adds the ID from a RecordRef. Null-safe.
addToScope(Context otherContext) Merges the scope from another Context (for delegation).
addError(callcoreio.Error error) Records a non-fatal error (e.g., ScopeTooLargeError).

Read Properties

Property Type Description
hasErrors Boolean True if any errors were added via addError.

Discriminator

The discriminator is RecordType:<SObjectApiName> where <SObjectApiName> is the API name of the object the strategy applies to (e.g., RecordType:Contact, RecordType:Opportunity__c).

Use default to provide a fallback for all object types that do not have a more specific record.

Default Behaviour

Object Default scope
Contact Contact + parent Account
Account Account + child Contacts
Opportunity Opportunity + Account (Account's default scope applies)
Anything else The anchor record only

Errors

callcoreio.ScopeTooLargeError is a built-in error type for when a query would return too many records to build a usable scope. Add it via context.addError(error) — the framework will surface it to the UI without halting execution.

global class ScopeTooLargeError extends callcoreio.Error {
    global List<callcoreio.RecordRef> contextRecords;
    global String relationSObjectApiName;
    global String relationshipName;
    global Integer relationCount;
    global Integer maxAllowedRelationCount;
}

Example: Custom Object with a Lookup to Account

A custom object Project__c has a Account__c lookup. When the timeline is viewed from a Project record, include the Project itself plus its linked Account.

public class BuildProjectCommsScope
    implements callcoreio.BuildCommunicationScopeForRecord.IStrategy {

    public void build(callcoreio.BuildCommunicationScopeForRecord.Context context) {
        Project__c project = [
            SELECT Id, Account__c
            FROM Project__c
            WHERE Id = :context.anchorRef.recordId
            LIMIT 1
        ];

        context
            .addToScope(project.Id)
            .addToScope(project.Account__c);
    }
}

Register with:

  • Strategy Type: BuildCommunicationScopeForRecord
  • Discriminator: RecordType:Project__c
  • Apex Class Name: BuildProjectCommsScope

Example: Delegating to Another Record's Scope

Use this pattern when your custom object has a lookup to a Contact and you want to inherit Contact's default scope behaviour — the Contact itself plus its parent Account — without reimplementing that logic. Rather than querying the Account directly, you call BuildCommunicationScopeForRecord.build with the Contact's ID and merge the result. If the Contact's scope logic is later changed (via its own registered strategy), your implementation picks up that change automatically.

public class BuildCaseCommsScope
    implements callcoreio.BuildCommunicationScopeForRecord.IStrategy {

    public void build(callcoreio.BuildCommunicationScopeForRecord.Context context) {
        Case c = [
            SELECT Id, ContactId
            FROM Case
            WHERE Id = :context.anchorRef.recordId
            LIMIT 1
        ];

        context.addToScope(c.Id);

        if (c.ContactId != null) {
            callcoreio.BuildCommunicationScopeForRecord.Context contactCtx =
                callcoreio.BuildCommunicationScopeForRecord.build(c.ContactId);

            context.addToScope(contactCtx);
        }
    }
}

Notes

  • The anchor record is not automatically added to scope. If you want it included, call context.addToScope(context.anchorRef) explicitly.
  • Records from different SObject types can be added to the same scope. The package groups them by type internally before passing to GatherPhoneNumbersFromRecords.
  • Scope building happens once per timeline request. Avoid SOQL inside loops — the anchor is a single record, but related queries should be written in bulk-safe fashion if you anticipate the strategy being invoked for multiple records in future.