FormulaShare V1.13 Jun '20

Patch release
 

Bugfix: Custom object trigger deletions remove shares for other records (Github)

Prior to this release, if the documented approach was used for trigger code on a custom object, the line below would have the effect of removing all FormulaShare sharing for records for this object other than the records being created or updated:

    delete helper.getSharesToDelete();

FormulaShare v1.1 Jun '19

Initial distributed version
 

Support for rule configuration via custom metadata

Standard and custom object support

Sharing to roles, roles and subordinates, users or groups

Batch job can be scheduled for full rule recalculation

Real time assessment triggered by calling global class methods

Logging of scheduled recalculations

OAuth 2.0 Login and Consent

A number of the OAuth 2.0 flows (OIDC Connect, Web Server, User-Agent, Device Authorisation etc) rely on authentication (login) and authorisation (consent to requested scopes) being handled in an interaction between the client app and the authorisation server.

In the diagrams in other sections, this is shown as a simplified "Authentication and Consent" step or similar. The diagram below shows in a bit more detail the steps involved in a typical interaction where both authentication and consent are needed.

Note that there are variations of this flow - e.g. in OAuth with SAML, authentication to the authorisation server is handled through SAML.
 

Login and Consent Diagram


If Salesforce is acting as the authorisation server, relevant endpoints are:

  • Authorisation endpoint: <mydomainname>.my.salesforce.com/services/oauth2/authorize
  • Login page: <mydomainname>.my.salesforce.com
  • Authorisation page:  <mydomainname>.my.salesforce.com/_ui/identity/oauth/ui/AuthorizationPage
  • Token endpoint:  <mydomainname>.my.salesforce.com/services/oauth2/token

FormulaShare Release Notes


v2.0 TBD

  • Lightning interface to define and monitor rules
  • Sharing of object based on content of fields in a related object
  • Ability to share to either roles and internal subordinates, or internal and portal (external) subordinates
  • Selectively trigger calculation for a single object
  • Improved logging of calculation job outputs


v1.11 Oct '19

  • Bypass calculation if batch job run when no rules defined in org


v1.1 Jun '19

Initial distributed version

  • Support for rule configuration via custom metadata
  • Standard and custom object support
  • Sharing to roles, roles and subordinates, users or groups
  • Batch job can be scheduled for full rule recalculation
  • Real time assessment triggered by calling global class methods
  • Logging of scheduled recalculations

Configuration Guide (Versions 1.13 and below)

NOTE: This guide covers the released FormulaShare versions up to v1.13. The updated help guide has been written for FormulaShare version 2.0 and higher, which would apply for any upgrades or installations from the AppExchange since 16 November 2020, as well as most sandboxes.

If you're not sure which version you're on, you can check this by looking for FormulaShare in the Installed Packages menu item in Setup - if version number starts with a 2 then your org has been upgraded.

 

In this guide, we’ll walk through the steps to install the FormulaShare package in a Salesforce org, create a FormulaShare rule and check that it’s working as expected.

Package installation

The simplest way to manage installation and upgrades is to install the managed package to a sandbox or production org from the AppExchange listing: https://appexchange.salesforce.com/appxListingDetail?listingId=a0N3A00000FR5TCUA1

AppExchange Listing

 

The source code and all metadata configuration for FormulaShare is available on Github. Deploying to an org from files on Github is also possible, though out of scope of this guide.

 

Post installation setup

The first step to get going after installation is to schedule the FormulaShare batch job. This is the process used by the app to calculate and apply sharing.

To do this, navigate to the Salesforce Setup menu, type “Apex Classes” and click on the menu item. Click the “Schedule Apex button shown below:

Schedule Apex


Select the class “FormulaShareProcessSchedulable” to be scheduled.

Job Name can be anything - this distinguishes the processing job in the setup menu.
Apex Class should be set to “FormulaShareProcessSchedulable”.

Other parameters can be set to your preferred values. We’d recommend having the job run every day by setting Frequency to “Weekly” and ticking all of the days of the week.

Now we’re ready to configure some sharing logic!

 

Defining a sharing requirement

Sharing is all about who sees what. Describing sharing can feel abstract without a real world example, so the descriptions and screenshots in this guide all relate to the scenario below.

Let’s say we’re working for an international NGO, who fundraise donations for projects across Sub-Saharan Africa.

We hold records of donations in a custom object called... “Donation”. Donations are made for specific programmes running in one of the countries our NGO works in, and should be visible to the in-country finance staff working on those programmes:

Example Data Model

The trouble is, our organisation is pretty big, and works in over 60 countries. Even if we could identify the country for the Donation object in a field, we wouldn’t be able to use criteria-based sharing to share to each of the country roles without bumping up against the Salesforce limit.

So, we’ll instead set up some FormulaShare sharing for the Donation object which makes use of its relationships with other objects.

 

1: A field on the object to be shared

We know what we want to share, right? Great!

FormulaShare can share any standard or custom object which supports sharing. That is to say, objects which aren’t on the detail side of a master-detail relationship, and have their org-wide default sharing setting set as either Private or Public Read Only.

For FormulaShare to know who should get access, we need a field on the object to be shared which has this information. This field can hold either the name or record id of the entity needing access. Supported entity types are:

  • Users
  • Public Group
  • Roles

In the screenshot below, we’re setting up a field on Donation which holds the name of the Finance Manager Role (a text field on the country records):

Donation Formula Field


We can see the field populating below:

Poplated Formula Field


Note: If sharing to a role or public group, the exact Role Name or Group Name with should be populated in this field. This is shown against the specific role or public group in the setup menu.

It’s also possible to use the record id of a role or group here and configure the rule to use this instead.

In the case of sharing to a particular user, this must be done by populating record id (name is not supported).

 

2: Apex sharing reason for custom objects

The Apex Sharing Reason feature exists to help to manage different kinds of sharing on the same custom object. This is Salesforce’s way of applying a label to each sharing record so that it’s clear where this sharing came from.

If the object you want to share is a custom object, it’s recommended to set up a different sharing reason for each FormulaShare rule we need:

Apex Sharing Reasons


Initial setup of the sharing reason can only currently be done in Classic, so switch to this if necessary (click your picture in the top right and “Switch to Salesforce Classic”). Next open the setup page for the object to be shared (Setup -> Create -> Objects and click the object name). Scroll to “Apex Sharing Reasons”, click New, and set a reason label and name:

Apex Sharing Reason Definition


Copy the text of the name. This will be used in the next step.

NOTE: This step isn’t needed for standard objects, as Salesforce does not allow custom sharing reasons. See the end of the guide for more information on differences between FormulaShare used on custom and standard objects.

 

3: A FormulaShare Rule

Now that our records indicate who they need to be shared with, we can specify a rule to apply this sharing.

Click Setup and open “Custom Metadata Types”. Open “FormulaShare Rule”, and click the “Manage FormulaShare Rules” button at the top. From here click “New” to start defining the rule.

  • Name and Label: Add something to distinguish this rule from others
  • Shared Object: The API name (including "__c") of the object with records to be shared. Object must be set to Private (for Read or Edit access levels) or Public Read Only (for Edit access level), and must support sharing - child objects in a master-detail relationship and some standard objects do not support independent sharing rules
  • Shared To Field: The API name (including "__c") of the field on the object above which identifies who to share records with. The field can return either the Salesforce 15 or 18 character Id of the entity to be shared to, or the role or group name (developer name) when the rule provides this sharing
  • Shared to Field Type: Either "Id" or "Name", depending on return type of the Shared To Field
  • Share With: The type of entity this rule should share with. Options are "Users", "Roles", "Roles and Internal Subordinates", "Roles, Internal and Portal Subordinates" (includes both community and portal users) and "Public Groups"
  • Access Level: Set to Read or Edit
  • Sharing Reason: For custom objects, paste the name of the Apex Sharing Reason copied in the last step and add “__c”. For standard objects, leave this blank.

Here’s an example of the rule to share our donation object with the role and subordinates of the in country finance manager role:

Rule Metadata Example

 

4: Real time processing

FormulaShare is designed to be implemented without any coding needed - in this case rules will recalculate each time the scheduled batch job runs (daily, if the job is set up in this way).

For more instant results, a very simple bit of custom development can ensure FormulaShare applies or revokes sharing every time a shared object is created or updated. This step is optional - without this sharing will still be assessed and applied every time the scheduled job runs, which is fine if users don't need access right away.

To get real time assessment, the following code should be called from the shared object’s trigger (after insert and update):

    sdfs.FormulaShareHelper helper = new sdfs.FormulaShareHelper();
    insert helper.getSharesToInsert();
    delete helper.getSharesToDelete();

In our example, the apex trigger below will add or remove FormulaShare sharing where necessary for the Donation object each time donations are created or updated in a way which needs a sharing change:

    trigger DonationTrigger on Donation__c (after insert, after update) {
        sdfs.FormulaShareHelper helper = new sdfs.FormulaShareHelper();
        insert helper.getSharesToInsert();
        delete helper.getSharesToDelete();
    }

If implementing a trigger in this way, a corresponding test class like the one below is needed to give full code coverage:

    @IsTest public class DonationTriggerTest {
        @IsTest
        public static void testInsert() {
            Donation__c d = new Donation__c();
            insert d;
            System.assert(d.Id != null);
        }
    }

Note this is an illustration of a simple implementation where no other trigger code exists, no trigger helper / handler is used, and the shared object does not have any mandatory fields.

If trigger helper / handler classes or a trigger framework is used in your org, code to call FormulaShare methods can be added to an appropriate place in the methods managing record inserts or updates.

Note that FormulaShare functionality will assess whether any changes to sharing are required, and only update records when necessary. This means it’s not necessary to check these conditions before calling FormulaShare.

 

Check that sharing is working

Sharing will be updated when triggers run (see step above), or each time the batch jobs runs (for example daily - see “Post Installation Setup”).

There are a few ways to check that sharing is being applied as expected:

  1. Log in as a user who should now have access, and check they can view or edit the record
  2. Query the object’s share table using SOQL (for example select Id, UserOrGroupId, RowCause from Donation__Share where ParentId = <id of record which should be shared>)
  3. Click the “Sharing” button from the record in Salesforce Classic

To check sharing on the record in the UI (number 3 above), switch to Salesforce Classic if necessary, navigate to the record and click “Sharing”:

Sharing Button

Note that if you don’t see the sharing button, this could be due to one of the reasons below:

  • Sharing button is not on the page layout
  • Your user does not have full access to the record (this will be the case if you’re not the record owner or a system admin)
  • The object’s organisation-wide default is public read/write. In this case sharing is not relevant for the object as all users can view and edit all records, so FormulaShare rules will be ignored

The list shown will include any sharing applied by FormulaShare, as well as other sharing relevant to this record:

Applied Sharing


Note that the “Reason” shown corresponds to the Apex Sharing Reason set up in step 2.

 

Additional things to be aware of...

 

Standard vs custom objects

For custom objects, Apex Sharing Reasons enable FormulaShare to distinguish sharing applied by the app, and other apex and manual sharing used on the object. When records change in a way that FormulaShare sharing is no longer needed, the FormulaShare sharing under this Apex Sharing Reason no longer meeting the criteria of the FormulaShare rule are deleted.

For standard objects, sharing reasons aren't available, so FormulaShare can’t be sure whether sharing on a record was applied by FormulaShare or manually. To tackle this situation, FormulaShare provides two options for managing sharing on standard objects.
 

Standard Objects Option 1 - Additive

By default, sharing for standard objects will be added by FormulaShare but not removed. This means if there’s a data change which means that different sharing should apply, the new sharing will be created, but the old sharing not removed. For example, say FormulaShare shares Contacts to a public group which is set on the Country record they’re linked to. If a contact was linked to Malawi, it would be shared with the Malawi public group. If the contact is later changed to be associated with Zimbabwe instead, it would be shared with the Malawi public group, but also continue to be shared with the Zimbabwe public group.
 

Standard Objects Option 2 - Fully Managed

If requirements are such that sharing must be removed on a standard object, FormulaShare can be configured to remove ALL sharing on an object which doesn’t meet the criteria of the current active rules. This will remove any FormulaShare sharing which is no longer applicable, but will ALSO remove any other apex sharing and manual sharing applied in the org. This option should only be used if we’re sure manual sharing and apex sharing are not used on the object.

To set FormulaShare up to process an object in this way, create a record in the “FormulaShare Std Object to Remove Shares” custom metadata type.

 

FormulaShare Logs

Log records are created each time a batch job runs. These indicate the processing time of the batch job and the objects which have had sharing recalculated. To access logs, check the object “FormulaShare Logs”, which is available to all admins in the org, as well as any users who are assigned the permission set “FormulaShare Admin User"

About FormulaShare

FormulaShare logo winking

 

FormulaShare is a Salesforce app, available on the AppExchange and offered in free and subscription versions

Created to address limitations with native Salesforce sharing, FormulaShare allows formula fields, text fields and lookups to define who Salesforce records should be shared with. FormulaShare can substantially reduce the number of sharing rules and sharing automation in an org, and cater to use cases not possible with out-of-the-box features.

  • Records are shared to entities specified in a formula, lookup or text field on the record itself
  • This field can be on the record itself, or on a related record associated through a series of lookups
  • Sharing to users, roles and public groups is supported in all versions, with Enterprise and Unlimited also supporting manager groups and members of a user's default account or opportunity team
  • Sharing changes are assessed in real time as shared records are created and modified
  • Several batch calculation options are available to cater to orgs of all sizes and data volumes 
  • Rules are custom metadata, so can be managed by admins and packaged for deployment
  • Standard and custom objects are supported, and both Classic and Lightning can be used

The app has passed the rigorous Salesforce security review. The app is offered under an open-core model, with the core sharing assessment engine publicly available on Github for users to review. Contributions to the public repo are welcome - get in touch or send us a pull request!