BuildScopeForRecord

Overview

Step 1 of the programmatic access pipeline. Given a Salesforce record ID, resolves which records are "in scope" for communications using the BuildCommunicationScopeForRecord strategy. The strategy determines — for any given context record (e.g. an Opportunity) — which related records should be searched for phone numbers and activity links (e.g. the Opportunity itself plus its related Account and Contacts).

The result is a RecordRefSets — an immutable collection of record references grouped by SObject type. Use getScope() to inspect it, excluding(Id) to narrow it, then call one of the conversion methods to continue:

  • toGatherPhoneNumbersRequest() → feeds step 2 of the call path (GatherPhoneNumbersInScope)
  • toGetEmailMessageIdsRequest() → feeds step 3 of the email path (GetEmailMessageIds) — emails are record-scoped, not phone-number-scoped

The same scope response can feed both paths independently.

Request

Construct the Request directly and pass it to the handler:

BuildScopeForRecord.IHandler handler =
    BuildScopeForRecord.construct(SharingRule.WithSharing);

BuildScopeForRecord.Response scopeResult =
    handler.execute(new BuildScopeForRecord.Request(recordId));
Parameter Type Required Description
recordId Id Yes The Salesforce record to resolve scope for. Must not be null.

The SharingRule passed to construct() is forwarded to the BuildCommunicationScopeForRecord strategy — use WithSharing to respect the running user's CRM record visibility when the strategy queries related records.

Response

Member Type Description
getScope() RecordRefSets In-scope records, grouped by SObject type.
excluding(Id recordId) Response Removes a record from scope. Narrowing only — callers cannot add records not produced by the strategy. Fluent.
toGatherPhoneNumbersRequest() GatherPhoneNumbersInScope.Request Converts to a request for step 2 of the call path.
toGetEmailMessageIdsRequest() GetEmailMessageIds.Request Converts to a request for step 3 of the email path.

Both conversion methods can be called on the same Response independently — the scope is not consumed.

Testing

MockBuildScopeForRecord is a package-provided test double. Call use() to install it for the current test transaction, then returning() to configure the scope it will produce. The real strategy and scope-building logic are bypassed entirely.

@isTest
static void myTest() {
    MockBuildScopeForRecord.use()
        .returning(RecordRefSets.empty());

    // Your code that calls BuildScopeForRecord receives the configured scope.
    MyService.run(someRecordId);
}

The mock ignores the input record ID and always returns the configured RecordRefSets. Use RecordRefSets.empty() when scope contents do not affect the assertion being made, or supply a populated scope to drive downstream behaviour.

Method Description
use() Installs this instance as the handler for the current test transaction. Returns the instance for chaining.
returning(RecordRefSets scope) Configures the scope returned by execute(). Passing null is equivalent to RecordRefSets.empty().