Skip to content

Commit

Permalink
Enable rollup bypass via Custom Setting, Dev API, or per-rollup Cust …
Browse files Browse the repository at this point in the history
…Perm
  • Loading branch information
aheber committed Nov 24, 2024
1 parent e9f9de6 commit 45cd658
Show file tree
Hide file tree
Showing 17 changed files with 268 additions and 69 deletions.
26 changes: 14 additions & 12 deletions dlrs/main/classes/BypassHandler.cls
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,31 @@
* The bypass and removebypass method return the result of the default Set object operations.
**/
public without sharing class BypassHandler {
private static Set<String> bypassedRollups;
private static Set<String> bypassedRollups = new Set<String>();
private static Boolean bypassAll = false;

/**
* Initialize the set if necessary for adding rollups to the bypass list.
* Checks if the rollup is bypassed or not. Returns true if it is. False otherwise.
* Could be bypassed by custom setting, bypass all, or specific named bypass
*/
private static void init() {
if (bypassedRollups == null) {
bypassedRollups = new Set<String>();
}
public static Boolean isBypassed(String handlerName) {
return DeclarativeLookupRollupSummaries__c.getInstance()
.DisableDLRSGlobally__c == true ||
bypassAll ||
bypassedRollups.contains(handlerName);
}

/**
* Checks if the rollup is bypassed or not. Returns true if it is. False otherwise.
* Sets a global bypass value, if true all rollups will be disabled for execution
*/
public static Boolean isBypassed(String handlerName) {
return bypassedRollups != null && bypassedRollups.contains(handlerName);
public static void setBypassAll(Boolean val) {
bypassAll = val;
}

/**
* Adds a rollup to the bypassed rollups list.
*/
public static Boolean bypass(String handlerName) {
init();

if (handlerName != null) {
System.debug(
LoggingLevel.INFO,
Expand All @@ -75,7 +76,7 @@ public without sharing class BypassHandler {
* Clears the bypass for a single rollup.
*/
public static Boolean clearBypass(String handlerName) {
if (bypassedRollups != null && handlerName != null) {
if (handlerName != null) {
System.debug(
LoggingLevel.INFO,
'DLRS trigger handler is no longer bypassed: ' + handlerName
Expand All @@ -95,6 +96,7 @@ public without sharing class BypassHandler {
* Clears all bypasses, if any.
*/
public static void clearAllBypasses() {
bypassAll = false;
if (bypassedRollups != null) {
bypassedRollups.clear();
}
Expand Down
83 changes: 57 additions & 26 deletions dlrs/main/classes/BypassHandlerTest.cls
Original file line number Diff line number Diff line change
Expand Up @@ -28,54 +28,85 @@ private class BypassHandlerTest {
@IsTest
static void testApi() {
String rollupUniqueName = 'SampleRollup';
Boolean bypassResult;

Test.startTest();
System.assertEquals(
false,
Assert.isFalse(
BypassHandler.isBypassed(rollupUniqueName),
'The rollup should not be bypassed yet.'
);
bypassResult = BypassHandler.bypass(rollupUniqueName);
System.assert(
bypassResult,

Assert.isTrue(
BypassHandler.bypass(rollupUniqueName),
'Should have modified the bypassed rollups set.'
);
System.assertEquals(
true,
Assert.isTrue(
BypassHandler.isBypassed(rollupUniqueName),
'The rollup should be bypassed.'
);
bypassResult = BypassHandler.clearBypass(rollupUniqueName);
System.assert(
bypassResult,

Assert.isTrue(
BypassHandler.clearBypass(rollupUniqueName),
'Should have modified the bypassed rollups set.'
);
System.assertEquals(
false,
Assert.isFalse(
BypassHandler.isBypassed(rollupUniqueName),
'The rollup should not be bypassed anymore.'
);
BypassHandler.bypass(rollupUniqueName);
BypassHandler.clearAllBypasses();
System.assertEquals(
false,
Assert.isFalse(
BypassHandler.isBypassed(rollupUniqueName),
'The rollup should not be bypassed anymore.'
);

bypassResult = BypassHandler.bypass(null);
System.assertEquals(
false,
bypassResult,
Assert.isFalse(
BypassHandler.bypass(null),
'Should return "false" for a null rollup name.'
);
bypassResult = BypassHandler.clearBypass(null);
System.assertEquals(
false,
bypassResult,

Assert.isFalse(
BypassHandler.clearBypass(null),
'Should return "false" for a null rollup name.'
);
Test.stopTest();

BypassHandler.setBypassAll(true);
Assert.isTrue(
BypassHandler.isBypassed(rollupUniqueName),
'Should return "true" for all rollup names.'
);
Assert.isTrue(
BypassHandler.isBypassed('new name'),
'Should return "true" for all rollup names.'
);
BypassHandler.setBypassAll(false);

Assert.isFalse(
BypassHandler.isBypassed(rollupUniqueName),
'Should return "false" for all rollup names.'
);
Assert.isFalse(
BypassHandler.isBypassed('new name'),
'Should return "false" for all rollup names.'
);
BypassHandler.setBypassAll(true);
Assert.isTrue(
BypassHandler.isBypassed('new name'),
'Should return "true" for all rollup names.'
);
BypassHandler.clearAllBypasses();
Assert.isFalse(
BypassHandler.isBypassed('new name'),
'Should return "false" for all rollup names.'
);
}

@IsTest
static void testCustomSettingDisable() {
String rollupUniqueName = 'Rollup1';
Assert.isFalse(BypassHandler.isBypassed(rollupUniqueName));

DeclarativeLookupRollupSummaries__c settings = DeclarativeLookupRollupSummaries__c.getInstance();
settings.DisableDLRSGlobally__c = true;
insert settings;

Assert.isTrue(BypassHandler.isBypassed(rollupUniqueName));
}
}
4 changes: 4 additions & 0 deletions dlrs/main/classes/RollupEditorController.cls
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,8 @@ public with sharing class RollupEditorController {
@AuraEnabled
public String aggregateResultField;
@AuraEnabled
public String bypassPermissionApiName;
@AuraEnabled
public String calculationMode;
@AuraEnabled
public String calculationSharingMode;
Expand Down Expand Up @@ -309,6 +311,7 @@ public with sharing class RollupEditorController {
this.aggregateAllRows = record.AggregateAllRows__c;
this.aggregateOperation = record.AggregateOperation__c;
this.aggregateResultField = record.AggregateResultField__c;
this.bypassPermissionApiName = record.BypassPermissionApiName__c;
this.calculationMode = record.CalculationMode__c;
this.calculationSharingMode = record.CalculationSharingMode__c;
this.childObject = record.ChildObject__c;
Expand All @@ -335,6 +338,7 @@ public with sharing class RollupEditorController {
record.AggregateAllRows__c = this.aggregateAllRows;
record.AggregateOperation__c = this.aggregateOperation;
record.AggregateResultField__c = this.aggregateResultField;
record.BypassPermissionApiName__c = this.bypassPermissionApiName;
record.CalculationMode__c = this.calculationMode;
record.CalculationSharingMode__c = this.calculationSharingMode;
record.ChildObject__c = this.childObject;
Expand Down
27 changes: 23 additions & 4 deletions dlrs/main/classes/RollupService.cls
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,13 @@ global with sharing class RollupService {
return BypassHandler.bypass(rollupName);
}

/**
* Allow the bypass of all rollups for this transaction, can be cleared with "clearAllBypasses" method
*/
global static void bypassAll() {
BypassHandler.setBypassAll(true);
}

/**
* Clears the bypass of a rollup, given its unique name.
*/
Expand Down Expand Up @@ -964,7 +971,10 @@ global with sharing class RollupService {
// this avoids having to re-parse RelationshipCriteria & OrderBy fields during field change detection
Map<Id, Set<String>> fieldsInvolvedInLookup = new Map<Id, Set<String>>();
for (RollupSummary lookup : lookups) {
if (BypassHandler.isBypassed(lookup.UniqueName)) {
if (
Utilities.userHasCustomPermission(lookup.BypassCustPermApiName) ||
BypassHandler.isBypassed(lookup.UniqueName)
) {
continue;
}

Expand Down Expand Up @@ -1099,7 +1109,10 @@ global with sharing class RollupService {
// Build a revised list of lookups to process that includes only where fields used in the rollup have changed
List<RollupSummary> lookupsToProcess = new List<RollupSummary>();
for (RollupSummary lookup : lookups) {
if (BypassHandler.isBypassed(lookup.UniqueName)) {
if (
Utilities.userHasCustomPermission(lookup.BypassCustPermApiName) ||
BypassHandler.isBypassed(lookup.UniqueName)
) {
continue;
}

Expand Down Expand Up @@ -1134,7 +1147,10 @@ global with sharing class RollupService {
: existingRecords;
for (SObject childRecord : recordsToProcess.values()) {
for (RollupSummary lookup : lookups) {
if (BypassHandler.isBypassed(lookup.UniqueName)) {
if (
Utilities.userHasCustomPermission(lookup.BypassCustPermApiName) ||
BypassHandler.isBypassed(lookup.UniqueName)
) {
continue;
}

Expand Down Expand Up @@ -1179,7 +1195,10 @@ global with sharing class RollupService {
List<RollupSummary> runnowLookups = new List<RollupSummary>();
List<LookupRollupSummaryScheduleItems__c> scheduledItems = new List<LookupRollupSummaryScheduleItems__c>();
for (RollupSummary lookup : lookups) {
if (BypassHandler.isBypassed(lookup.UniqueName)) {
if (
Utilities.userHasCustomPermission(lookup.BypassCustPermApiName) ||
BypassHandler.isBypassed(lookup.UniqueName)
) {
continue;
}

Expand Down
54 changes: 29 additions & 25 deletions dlrs/main/classes/RollupServiceTest.cls
Original file line number Diff line number Diff line change
Expand Up @@ -2623,54 +2623,58 @@ private with sharing class RollupServiceTest {
@IsTest
static void testBypassApi() {
String rollupUniqueName = 'SampleRollup';
Boolean bypassResult;

Test.startTest();
System.assertEquals(
false,
Assert.isFalse(
RollupService.isBypassed(rollupUniqueName),
'The rollup should not be bypassed yet.'
);
bypassResult = RollupService.bypass(rollupUniqueName);
System.assert(
bypassResult,

Assert.isTrue(
RollupService.bypass(rollupUniqueName),
'Should have modified the bypassed rollups set.'
);
System.assertEquals(
true,
Assert.isTrue(
RollupService.isBypassed(rollupUniqueName),
'The rollup should be bypassed.'
);
bypassResult = RollupService.clearBypass(rollupUniqueName);
System.assert(
bypassResult,

Assert.isTrue(
RollupService.clearBypass(rollupUniqueName),
'Should have modified the bypassed rollups set.'
);
System.assertEquals(
false,
Assert.isFalse(
RollupService.isBypassed(rollupUniqueName),
'The rollup should not be bypassed anymore.'
);
RollupService.bypass(rollupUniqueName);
RollupService.clearAllBypasses();
System.assertEquals(
false,
Assert.isFalse(
RollupService.isBypassed(rollupUniqueName),
'The rollup should not be bypassed anymore.'
);

bypassResult = RollupService.bypass(null);
System.assertEquals(
false,
bypassResult,
Assert.isFalse(
RollupService.bypass(null),
'Should return "false" for a null rollup name.'
);
bypassResult = RollupService.clearBypass(null);
System.assertEquals(
false,
bypassResult,
Assert.isFalse(
RollupService.clearBypass(null),
'Should return "false" for a null rollup name.'
);
Test.stopTest();

RollupService.bypassAll();
Assert.isTrue(
RollupService.isBypassed(rollupUniqueName),
'Should return "true" for all rollup names.'
);
Assert.isTrue(
RollupService.isBypassed('new name'),
'Should return "true" for all rollup names.'
);
RollupService.clearAllBypasses();
Assert.isFalse(
RollupService.isBypassed(rollupUniqueName),
'Should return "false" for all rollup names.'
);
}
}
1 change: 1 addition & 0 deletions dlrs/main/classes/RollupSummariesSelector.cls
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ public class RollupSummariesSelector {
LookupRollupSummary2__mdt.Active__c,
LookupRollupSummary2__mdt.AggregateOperation__c,
LookupRollupSummary2__mdt.AggregateResultField__c,
LookupRollupSummary2__mdt.BypassPermissionApiName__c,
LookupRollupSummary2__mdt.CalculationMode__c,
LookupRollupSummary2__mdt.ChildObject__c,
LookupRollupSummary2__mdt.ConcatenateDelimiter__c,
Expand Down
15 changes: 15 additions & 0 deletions dlrs/main/classes/RollupSummary.cls
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,21 @@ public class RollupSummary {
}
}

public String BypassCustPermApiName {
get {
if (Record instanceof LookupRollupSummary2__mdt) {
return (String) Record.get('BypassPermissionApiName__c');
} else {
return null;
}
}
set {
if (Record instanceof LookupRollupSummary2__mdt) {
Record.put('BypassPermissionApiName__c', value);
}
}
}

public String CalculationMode {
get {
return (String) Record.get('CalculationMode__c');
Expand Down
23 changes: 23 additions & 0 deletions dlrs/main/classes/RollupSummaryTest.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
@IsTest
public class RollupSummaryTest {
@IsTest
static void testBypassCustPermApiName() {
LookupRollupSummary2__mdt rollup = new LookupRollupSummary2__mdt();
rollup.BypassPermissionApiName__c = null;
RollupSummary rs = new RollupSummary(rollup);
Assert.areEqual(null, rs.BypassCustPermApiName);
rollup.BypassPermissionApiName__c = 'Rollup1';
rs = new RollupSummary(rollup);
Assert.areEqual('Rollup1', rs.BypassCustPermApiName);

rs.BypassCustPermApiName = 'Rollup2';
Assert.areEqual('Rollup2', rs.BypassCustPermApiName);

LookupRollupSummary__c rollupCO = new LookupRollupSummary__c();
rs = new RollupSummary(rollupCO);
Assert.areEqual(null, rs.BypassCustPermApiName);
rs.BypassCustPermApiName = 'Rollup1';
// we're not building support in the Custom Object rollup versions, setting the value is ignored
Assert.areEqual(null, rs.BypassCustPermApiName);
}
}
Loading

0 comments on commit 45cd658

Please sign in to comment.