Skip to content

Commit

Permalink
v1.6.34 - Bugfixes! (#628)
Browse files Browse the repository at this point in the history
* Removes GAP_CREATE and GAP_UPDATE from CDC handling as those are not valid CDC cases for rolling up

* Fixes an issue with the Rollup_Field_Parent_Required validation rule on Rollup__mdt

* Fixes #619 by more carefully handling parentRecordIdForEmptyChildrenCollections variable

* Updates jsconfig.json with new CLI-based changes

* Removes heap size checks as they are unncessarily expensive when checking rollup limits

* Fixes #626 by patching a few places where RollupControl__mdt being null (which is sometimes set internally by the framework for performance reasons) does not cause issues when trying to log

* Fixes #623 by properly parsing nested IN conditions during recursive where clause operations

* Fixes #622 by properly tracking changes to calc items when updates occur with differing values for multicurrency orgs

* Fixes an issue where sync rollups enqueued by Flow would not run in the proper order

* Attempted fix for #625 - do not allow max query rows to exceed the platform limit


* Fixes an issue reported by Katherine West where multiple order bys were sometimes omitted in RollupRepository queries due to an inner ordering - moved the ordering to in-memory sorting
  • Loading branch information
jamessimone authored Sep 26, 2024
1 parent 3a75005 commit 91dfd99
Show file tree
Hide file tree
Showing 27 changed files with 486 additions and 105 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ sfge-*.log.gz
.DS_Store
.config
.vscode
config/data/act-pr-event.json
config/data/act-pr-event.json
.sflogsub
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ As well, don't miss [the Wiki](../../wiki), which includes even more info for co

## Deployment & Setup

<a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008ObeQAAS">
<a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OfJfAAK">
<img alt="Deploy to Salesforce"
src="./media/deploy-package-to-prod.png">
</a>

<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008ObeQAAS">
<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008OfJfAAK">
<img alt="Deploy to Salesforce Sandbox"
src="./media/deploy-package-to-sandbox.png">
</a>
Expand Down
21 changes: 19 additions & 2 deletions extra-tests/classes/InvocableDrivenTests.cls
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ private class InvocableDrivenTests {
@TestSetup
static void setup() {
upsert new RollupSettings__c(IsEnabled__c = true);
Account acc = new Account(Name = InvocableDrivenTests.class.getName());
insert acc;
insert new Account(Name = InvocableDrivenTests.class.getName());
}

@IsTest
Expand Down Expand Up @@ -182,4 +181,22 @@ private class InvocableDrivenTests {
parent = [SELECT AnnualRevenue FROM Account WHERE Id = :parent.Id];
System.assertEquals(null, parent.AnnualRevenue);
}

@IsTest
static void refreshWorksWithEmptyCollectionsWhenParentIdIsProvided() {
Account acc = [SELECT Id FROM Account];
ContactPointAddress child = new ContactPointAddress(Name = 'RollupIntegrationRefresh', PreferenceRank = 99, ParentId = acc.Id);
insert child;

Flow.Interview flowInterview = new Flow.Interview.Rollup_Integration_Refresh_With_Empty_Collections(
new Map<String, Object>{ 'parentRecordIdForEmptyChildrenCollections' => acc.Id }
);

Test.startTest();
flowInterview.start();
Test.stopTest();

acc = [SELECT AnnualRevenue FROM Account WHERE Id = :acc.Id];
System.assertEquals(child.PreferenceRank, acc.AnnualRevenue);
}
}
8 changes: 8 additions & 0 deletions extra-tests/classes/RollupCurrencyInfoTests.cls
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ private class RollupCurrencyInfoTests {
RollupCurrencyInfo.transform(new List<SObject>{ camp }, Campaign.ActualCost, mockEurInfo.IsoCode, new List<RollupOrderBy__mdt>());
updatedCamp = (Campaign) RollupCurrencyInfo.getCalcItem(camp, mockEurInfo.IsoCode);
System.assertEquals((mockEurInfo.ConversionRate / (mockUsdInfo.ConversionRate / camp.ActualCost)).doubleValue(), updatedCamp.ActualCost);
// sanity check that updates on previously transformed fields still calculate correctly
camp.BudgetedCost = 6;
RollupCurrencyInfo.transform(new List<SObject>{ camp }, Campaign.BudgetedCost, mockEurInfo.IsoCode, new List<RollupOrderBy__mdt>());
Campaign again = (Campaign) RollupCurrencyInfo.getCalcItem(camp, mockEurInfo.IsoCode);
System.assertEquals(
(mockEurInfo.ConversionRate / (mockUsdInfo.ConversionRate / camp.BudgetedCost)).setScale(mockEurInfo.DecimalPlaces),
again.BudgetedCost
);
}

@IsTest
Expand Down
9 changes: 9 additions & 0 deletions extra-tests/classes/RollupEvaluatorTests.cls
Original file line number Diff line number Diff line change
Expand Up @@ -1258,6 +1258,15 @@ private class RollupEvaluatorTests {
System.assertEquals(false, eval.matches(nonMatch3));
}

@IsTest
static void stripsExtraParantheticalStructures() {
String whereClause = '(Name IN (\'0-Current\', \'1-30 Days\', \'31-60 Days\')) AND Name IN (\'0-Current\', \'1-30 Days\', \'31-60 Days\')';

RollupEvaluator eval = new RollupEvaluator.WhereFieldEvaluator(whereClause, ContactPointConsent.SObjectType);

System.assertEquals(true, eval.matches(new ContactPointConsent(Name = '0-Current')));
}

private static String getSoqlCompliantDatetime(Datetime dt) {
return dt.format('yyyy-MM-dd\'T\'HH:mm:ssZ');
}
Expand Down
11 changes: 10 additions & 1 deletion extra-tests/classes/RollupLimitsTest.cls
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
private class RollupLimitsTest {
@IsTest
static void correctlyReferencesOrgLimits() {
System.assertEquals(false, new RollupLimits.Tester(RollupControl__mdt.getInstance('Org_Default'), false).hasExceededOrgAsyncLimit());
Assert.areEqual(false, new RollupLimits.Tester(RollupControl__mdt.getInstance('Org_Default'), false).hasExceededOrgAsyncLimit());
}

@IsTest
static void doesNotThrowForNullControl() {
RollupLimits.stubbedQueryRows = 50001;

Boolean hasExceededLimits = Rollup.hasExceededCurrentRollupLimits(null);

Assert.isTrue(hasExceededLimits);
}
}
34 changes: 34 additions & 0 deletions extra-tests/classes/RollupRepositoryTests.cls
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,40 @@ private class RollupRepositoryTests {
Assert.isNull(ex);
}

@IsTest
static void orderBysEndUpCorrectlySorter() {
List<RollupOrderBy__mdt> orderBys = new List<RollupOrderBy__mdt>{
new RollupOrderBy__mdt(Ranking__c = 3, DeveloperName = 'd'),
new RollupOrderBy__mdt(Ranking__c = 0, DeveloperName = 'a'),
new RollupOrderBy__mdt(Ranking__c = 1, DeveloperName = 'b'),
new RollupOrderBy__mdt(Ranking__c = 2, DeveloperName = 'c')
};

orderBys.sort(new RollupRepository.OrderBySorter());

Assert.areEqual(0, orderBys.get(0).Ranking__c);
Assert.areEqual(1, orderBys.get(1).Ranking__c);
Assert.areEqual(2, orderBys.get(2).Ranking__c);
Assert.areEqual(3, orderBys.get(3).Ranking__c);
}

@IsTest
static void orderBysUseDeveloperNameForTieBreaker() {
List<RollupOrderBy__mdt> orderBys = new List<RollupOrderBy__mdt>{
new RollupOrderBy__mdt(Ranking__c = 0, DeveloperName = 'd'),
new RollupOrderBy__mdt(Ranking__c = 0, DeveloperName = 'a'),
new RollupOrderBy__mdt(Ranking__c = 0, DeveloperName = 'b'),
new RollupOrderBy__mdt(Ranking__c = 0, DeveloperName = 'c')
};

orderBys.sort(new RollupRepository.OrderBySorter());

Assert.areEqual('a', orderBys.get(0).DeveloperName);
Assert.areEqual('b', orderBys.get(1).DeveloperName);
Assert.areEqual('c', orderBys.get(2).DeveloperName);
Assert.areEqual('d', orderBys.get(3).DeveloperName);
}

/**
* Serialization proves that we don't get: `System.JSONException: Type unsupported in JSON: common.apex.methods.AccessLevelEnum`
*/
Expand Down
19 changes: 19 additions & 0 deletions extra-tests/classes/RollupSObjectUpdaterTests.cls
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,25 @@ public class RollupSObjectUpdaterTests {
Assert.areEqual('Update failed. First exception on row 0; first error: MISSING_ARGUMENT, Id not specified in an update call: []', message);
}

@IsTest
static void nullRollupControlDoesNotPreventExecution() {
RollupLimits.stubbedQueryRows = 50001;
RollupControl__mdt control = new RollupControl__mdt();
RollupSObjectUpdater updater = new RollupSObjectUpdater();

updater.forceSyncUpdate();
updater.addRollupControl(control);
control = null;

Exception ex;
try {
updater.doUpdate(new List<SObject>{ new Account(Id = RollupTestUtils.createId(Account.SObjectType)) });
} catch (Exception e) {
ex = e;
}
Assert.isNull(ex);
}

public class MockUpdater implements RollupSObjectUpdater.IUpdater {
public void performUpdate(List<SObject> recordsToUpdate, Database.DMLOptions options) {
mockUpdatedRecords = recordsToUpdate;
Expand Down
2 changes: 1 addition & 1 deletion extra-tests/classes/RollupTestUtils.cls
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class RollupTestUtils {
}

public static DMLMock loadAccountIdMock(List<SObject> records) {
Account acc = [SELECT Id FROM Account];
Account acc = [SELECT Id FROM Account LIMIT 1];
for (SObject record : records) {
record.put('ParentId', acc.Id);
}
Expand Down
1 change: 1 addition & 0 deletions extra-tests/classes/RollupTests.cls
Original file line number Diff line number Diff line change
Expand Up @@ -1362,6 +1362,7 @@ private class RollupTests {
RollupTestUtils.DMLMock mock = RollupTestUtils.loadMock(new List<ContactPointAddress>{ somethingElseName });
Rollup.oldRecordsMap = new Map<Id, SObject>{ somethingElseName.Id => somethingElseName };
Rollup.apexContext = TriggerOperation.BEFORE_DELETE;
Rollup.onlyUseMockMetadata = true;
Rollup.rollupMetadata = new List<Rollup__mdt>{
new Rollup__mdt(
CalcItem__c = 'ContactPointAddress',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
<?xml version="1.0" encoding="UTF-8" ?>
<CustomMetadata
xmlns="http://soap.sforce.com/2006/04/metadata"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
>
<label>Rollup Integration: REFRESH</label>
<protected>false</protected>
<values>
<field>CalcItemText__c</field>
<value xsi:type="xsd:string">ContactPointAddress</value>
</values>
<values>
<field>CalcItemWhereClause__c</field>
<value xsi:type="xsd:string">Name = &apos;RollupIntegrationRefresh&apos;</value>
</values>
<values>
<field>CalcItem__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>ChangedFieldsOnCalcItem__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>ConcatDelimiter__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>CurrencyFieldMapping__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>Description__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>FullRecalculationDefaultNumberValue__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>FullRecalculationDefaultStringValue__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>GrandparentRelationshipFieldPath__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>GroupByFields__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>GroupByRowEndDelimiter__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>GroupByRowStartDelimiter__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>IsDistinct__c</field>
<value xsi:type="xsd:boolean">false</value>
</values>
<values>
<field>IsFullRecordSet__c</field>
<value xsi:type="xsd:boolean">false</value>
</values>
<values>
<field>IsRollupStartedFromParent__c</field>
<value xsi:type="xsd:boolean">false</value>
</values>
<values>
<field>IsTableFormatted__c</field>
<value xsi:type="xsd:boolean">false</value>
</values>
<values>
<field>LimitAmount__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>LookupFieldOnCalcItemText__c</field>
<value xsi:type="xsd:string">ParentId</value>
</values>
<values>
<field>LookupFieldOnCalcItem__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>LookupFieldOnLookupObjectText__c</field>
<value xsi:type="xsd:string">Id</value>
</values>
<values>
<field>LookupFieldOnLookupObject__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>LookupObjectText__c</field>
<value xsi:type="xsd:string">Account</value>
</values>
<values>
<field>LookupObject__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>OneToManyGrandparentFields__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>OrderByFirstLast__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>RollupControl__c</field>
<value xsi:type="xsd:string">Org_Defaults</value>
</values>
<values>
<field>RollupFieldOnCalcItemText__c</field>
<value xsi:type="xsd:string">PreferenceRank</value>
</values>
<values>
<field>RollupFieldOnCalcItem__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>RollupFieldOnLookupObjectText__c</field>
<value xsi:type="xsd:string">AnnualRevenue</value>
</values>
<values>
<field>RollupFieldOnLookupObject__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>RollupGrouping__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>RollupOperation__c</field>
<value xsi:type="xsd:string">SUM</value>
</values>
<values>
<field>RollupToUltimateParent__c</field>
<value xsi:type="xsd:boolean">false</value>
</values>
<values>
<field>SharingMode__c</field>
<value xsi:nil="true" />
</values>
<values>
<field>ShouldRunWithoutCustomSettingEnabled__c</field>
<value xsi:type="xsd:boolean">false</value>
</values>
<values>
<field>SplitConcatDelimiterOnCalcItem__c</field>
<value xsi:type="xsd:boolean">false</value>
</values>
<values>
<field>UltimateParentLookup__c</field>
<value xsi:nil="true" />
</values>
</CustomMetadata>
Loading

0 comments on commit 91dfd99

Please sign in to comment.