From 1acc7d5a1b3ea3e01adab4be4b61d1736afa7552 Mon Sep 17 00:00:00 2001
From: James Simone <16430727+jamessimone@users.noreply.github.com>
Date: Wed, 2 Oct 2024 09:00:16 -0600
Subject: [PATCH] v1.6.35 - Rollup Order By Bugfix (#632)
* Fixes an issue reported by Katherine West where rollup ordering wasn't being properly applied
* Fixes #629 by properly handling text template HTML tags (when present) for the Full Recalc CMDT-driven Invocable rollup action
---
README.md | 4 +-
.../classes/RollupDateLiteralTests.cls | 9 ++-
.../RollupFlowFullRecalcDispatcherTests.cls | 75 +++++++++++++++++++
....Integration_NumberValue_FIRST.md-meta.xml | 29 +++++++
..._Comma_Separated_Full_Recalc.flow-meta.xml | 64 ++++++++++++++++
package.json | 2 +-
plugins/RollupCallback/README.md | 2 +-
rollup-namespaced/README.md | 4 +-
rollup-namespaced/sfdx-project.json | 7 +-
rollup/core/classes/RollupCalculator.cls | 3 +-
rollup/core/classes/RollupDateLiteral.cls | 18 ++++-
.../RollupFlowFullRecalcDispatcher.cls | 2 +-
rollup/core/classes/RollupLogger.cls | 2 +-
rollup/core/classes/RollupRepository.cls | 3 +-
sfdx-project.json | 10 +--
15 files changed, 210 insertions(+), 24 deletions(-)
create mode 100644 extra-tests/customMetadata/RollupOrderBy.Integration_NumberValue_FIRST.md-meta.xml
create mode 100644 extra-tests/flows/Rollup_Integration_Comma_Separated_Full_Recalc.flow-meta.xml
diff --git a/README.md b/README.md
index 581ad92f..8ca02079 100644
--- a/README.md
+++ b/README.md
@@ -24,12 +24,12 @@ As well, don't miss [the Wiki](../../wiki), which includes even more info for co
## Deployment & Setup
-
+
-
+
diff --git a/extra-tests/classes/RollupDateLiteralTests.cls b/extra-tests/classes/RollupDateLiteralTests.cls
index 1e7b374d..4ed69395 100644
--- a/extra-tests/classes/RollupDateLiteralTests.cls
+++ b/extra-tests/classes/RollupDateLiteralTests.cls
@@ -224,12 +224,15 @@ private class RollupDateLiteralTests {
@IsTest
static void shouldWorkForLastMonth() {
runTestForLiteral('LAST_MONTH');
+ User australiaUser = [SELECT Id FROM User WHERE LastName = 'Australia User'];
+ System.runAs(australiaUser) {
+ runTestForLiteral('LAST_MONTH');
+ }
}
@IsTest
static void shouldWorkForThisMonth() {
runTestForLiteral('THIS_MONTH');
- // TODO extend this more generally throughout this test class
User australiaUser = [SELECT Id FROM User WHERE LastName = 'Australia User'];
System.runAs(australiaUser) {
runTestForLiteral('THIS_MONTH');
@@ -239,6 +242,10 @@ private class RollupDateLiteralTests {
@IsTest
static void shouldWorkForNextMonth() {
runTestForLiteral('NEXT_MONTH');
+ User australiaUser = [SELECT Id FROM User WHERE LastName = 'Australia User'];
+ System.runAs(australiaUser) {
+ runTestForLiteral('NEXT_MONTH');
+ }
}
@IsTest
diff --git a/extra-tests/classes/RollupFlowFullRecalcDispatcherTests.cls b/extra-tests/classes/RollupFlowFullRecalcDispatcherTests.cls
index a84bba15..5dea8360 100644
--- a/extra-tests/classes/RollupFlowFullRecalcDispatcherTests.cls
+++ b/extra-tests/classes/RollupFlowFullRecalcDispatcherTests.cls
@@ -120,6 +120,81 @@ private class RollupFlowFullRecalcDispatcherTests {
System.assertEquals(5, user.Latitude);
}
+ @IsTest
+ static void supportsTextTemplateInputVariables() {
+ Rollup.onlyUseMockMetadata = true;
+ Rollup.rollupMetadata = new List{
+ new Rollup__mdt(
+ DeveloperName = 'cmdt1',
+ CalcItem__c = 'ContactPointAddress',
+ RollupFieldOnCalcItem__c = 'PreferenceRank',
+ LookupFieldOnCalcItem__c = 'ParentId',
+ LookupObject__c = 'Account',
+ LookupFieldOnLookupObject__c = 'Id',
+ RollupFieldOnLookupObject__c = 'AnnualRevenue',
+ RollupOperation__c = 'SUM',
+ CalcItemWhereClause__c = 'PreferenceRank = 1'
+ ),
+ new Rollup__mdt(
+ DeveloperName = 'cmdt2',
+ CalcItem__c = 'ContactPointAddress',
+ RollupFieldOnCalcItem__c = 'PreferenceRank',
+ LookupFieldOnCalcItem__c = 'ParentId',
+ LookupObject__c = 'Account',
+ LookupFieldOnLookupObject__c = 'Id',
+ RollupFieldOnLookupObject__c = 'NumberOfEmployees',
+ RollupOperation__c = 'COUNT'
+ )
+ };
+ List flowInputs = getFlowInputs(Rollup.rollupMetadata);
+ String exampleTextTemplate = '{0}
';
+ flowInputs[0].rollupDeveloperNames = String.format(exampleTextTemplate, new List{ flowInputs[0].rollupDeveloperNames });
+
+ Test.startTest();
+ RollupFlowFullRecalcDispatcher.performFullRecalcRollups(flowInputs);
+ Test.stopTest();
+
+ Account acc = [SELECT AnnualRevenue, NumberOfEmployees FROM Account];
+ System.assertEquals(6, acc.AnnualRevenue);
+ System.assertEquals(6, acc.NumberOfEmployees);
+ }
+
+ @IsTest
+ static void integrationSupportsTextTemplateVariables() {
+ Rollup.onlyUseMockMetadata = true;
+ Rollup.rollupMetadata = new List{
+ new Rollup__mdt(
+ DeveloperName = 'cmdt1',
+ CalcItem__c = 'ContactPointAddress',
+ RollupFieldOnCalcItem__c = 'PreferenceRank',
+ LookupFieldOnCalcItem__c = 'ParentId',
+ LookupObject__c = 'Account',
+ LookupFieldOnLookupObject__c = 'Id',
+ RollupFieldOnLookupObject__c = 'AnnualRevenue',
+ RollupOperation__c = 'SUM',
+ CalcItemWhereClause__c = 'PreferenceRank = 1'
+ ),
+ new Rollup__mdt(
+ DeveloperName = 'cmdt2',
+ CalcItem__c = 'ContactPointAddress',
+ RollupFieldOnCalcItem__c = 'PreferenceRank',
+ LookupFieldOnCalcItem__c = 'ParentId',
+ LookupObject__c = 'Account',
+ LookupFieldOnLookupObject__c = 'Id',
+ RollupFieldOnLookupObject__c = 'NumberOfEmployees',
+ RollupOperation__c = 'COUNT'
+ )
+ };
+
+ Test.startTest();
+ new Flow.Interview.Rollup_Integration_Comma_Separated_Full_Recalc(new Map{ 'rollupNames' => 'cmdt1, cmdt2' }).start();
+ Test.stopTest();
+
+ Account acc = [SELECT AnnualRevenue, NumberOfEmployees FROM Account];
+ System.assertEquals(6, acc.AnnualRevenue);
+ System.assertEquals(6, acc.NumberOfEmployees);
+ }
+
private static List getFlowInputs(List metas) {
List flowInputs = new List();
RollupFlowFullRecalcDispatcher.FlowInput input = new RollupFlowFullRecalcDispatcher.FlowInput();
diff --git a/extra-tests/customMetadata/RollupOrderBy.Integration_NumberValue_FIRST.md-meta.xml b/extra-tests/customMetadata/RollupOrderBy.Integration_NumberValue_FIRST.md-meta.xml
new file mode 100644
index 00000000..fa49e308
--- /dev/null
+++ b/extra-tests/customMetadata/RollupOrderBy.Integration_NumberValue_FIRST.md-meta.xml
@@ -0,0 +1,29 @@
+
+
+
+ false
+
+ FieldName__c
+ NumberField__c
+
+
+ NullSortOrder__c
+ NULLS FIRST
+
+
+ Ranking__c
+ 1.0
+
+
+ Rollup__c
+ RollupIntegrationChildRollupText
+
+
+ SortOrder__c
+ Ascending
+
+
diff --git a/extra-tests/flows/Rollup_Integration_Comma_Separated_Full_Recalc.flow-meta.xml b/extra-tests/flows/Rollup_Integration_Comma_Separated_Full_Recalc.flow-meta.xml
new file mode 100644
index 00000000..13a5e477
--- /dev/null
+++ b/extra-tests/flows/Rollup_Integration_Comma_Separated_Full_Recalc.flow-meta.xml
@@ -0,0 +1,64 @@
+
+
+
+ Recalc_Rollups
+
+ 176
+ 134
+ RollupFlowFullRecalcDispatcher
+ apex
+ CurrentTransaction
+
+ rollupDeveloperNames
+
+ Rollups_Comma_Separated
+
+
+ RollupFlowFullRecalcDispatcher
+ true
+ 1
+
+ 61.0
+ Default
+ Rollup Integration: Comma-Separated Full Recalc {!$Flow.CurrentDateTime}
+
+
+ BuilderType
+
+ LightningFlowBuilder
+
+
+
+ CanvasMode
+
+ AUTO_LAYOUT_CANVAS
+
+
+
+ OriginBuilderType
+
+ LightningFlowBuilder
+
+
+ AutoLaunchedFlow
+
+ 50
+ 0
+
+ Recalc_Rollups
+
+
+ Draft
+
+ Rollups_Comma_Separated
+ false
+ <p>{!rollupNames}</p>
+
+
+ rollupNames
+ String
+ false
+ true
+ false
+
+
diff --git a/package.json b/package.json
index 52b444a2..b56c89fa 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "apex-rollup",
- "version": "1.6.34",
+ "version": "1.6.35",
"description": "Fast, configurable, elastically scaling custom rollup solution. Apex Invocable action, one-liner Apex trigger/CMDT-driven logic, and scheduled Apex-ready.",
"repository": {
"type": "git",
diff --git a/plugins/RollupCallback/README.md b/plugins/RollupCallback/README.md
index 7192ab89..cceb6fa8 100644
--- a/plugins/RollupCallback/README.md
+++ b/plugins/RollupCallback/README.md
@@ -109,7 +109,7 @@ public class SubflowRollupDispatcher implements RollupSObjectUpdater.IDispatcher
decorator.FieldNames = new List(record.getPopulatedFieldsAsMap().keySet());
wrappedRecords.add(decorator);
}
- Flow.Interview rollupSubflow = Flow.Interview.RollupSubflow(
+ Flow.Interview rollupSubflow = new Flow.Interview.RollupSubflow(
new Map{
'records' => wrappedRecords
}
diff --git a/rollup-namespaced/README.md b/rollup-namespaced/README.md
index c3e0468a..dcc70b51 100644
--- a/rollup-namespaced/README.md
+++ b/rollup-namespaced/README.md
@@ -18,12 +18,12 @@ For more info, see the base `README`.
## Deployment & Setup
-
+
-
+
diff --git a/rollup-namespaced/sfdx-project.json b/rollup-namespaced/sfdx-project.json
index 227100ef..f84c61c0 100644
--- a/rollup-namespaced/sfdx-project.json
+++ b/rollup-namespaced/sfdx-project.json
@@ -4,8 +4,8 @@
"default": true,
"package": "apex-rollup-namespaced",
"path": "rollup-namespaced/source/rollup",
- "versionName": "Fixes parentRecordIdForEmptyChildrenCollections flow case",
- "versionNumber": "1.1.27.0",
+ "versionName": "Fixes Rollup Order By sorting to always be deterministic, allows text templates in Full Recalc CMDT-driven Invocable invocable",
+ "versionNumber": "1.1.28.0",
"versionDescription": "Fast, configurable, elastically scaling custom rollup solution. Apex Invocable action, one-liner Apex trigger/CMDT-driven logic, and scheduled Apex-ready.",
"releaseNotesUrl": "https://github.com/jamessimone/apex-rollup/releases/latest",
"unpackagedMetadata": {
@@ -30,6 +30,7 @@
"apex-rollup-namespaced@1.1.24": "04t6g000008ObbqAAC",
"apex-rollup-namespaced@1.1.25": "04t6g000008Obc0AAC",
"apex-rollup-namespaced@1.1.26": "04t6g000008ObeVAAS",
- "apex-rollup-namespaced@1.1.27": "04t6g000008OfJkAAK"
+ "apex-rollup-namespaced@1.1.27": "04t6g000008OfJkAAK",
+ "apex-rollup-namespaced@1.1.28": "04t6g000008OfKnAAK"
}
}
diff --git a/rollup/core/classes/RollupCalculator.cls b/rollup/core/classes/RollupCalculator.cls
index b4be10b7..82e7e8e4 100644
--- a/rollup/core/classes/RollupCalculator.cls
+++ b/rollup/core/classes/RollupCalculator.cls
@@ -321,8 +321,9 @@ public without sharing abstract class RollupCalculator {
protected List winnowItems(List items, Map oldCalcItems) {
List orderBys = this.metadata?.LimitAmount__c != null && this.metadata.RollupOrderBys__r.isEmpty()
? new List{ new RollupOrderBy__mdt(FieldName__c = 'Id', Ranking__c = 0) }
- : this.metadata.RollupOrderBys__r;
+ : new List(this.metadata.RollupOrderBys__r);
if (orderBys.isEmpty() == false) {
+ orderBys.sort(new RollupRepository.OrderBySorter());
items.sort(new RollupCalcItemSorter(orderBys));
}
List winnowedItems = new List();
diff --git a/rollup/core/classes/RollupDateLiteral.cls b/rollup/core/classes/RollupDateLiteral.cls
index 046cc0c6..4bad05c4 100644
--- a/rollup/core/classes/RollupDateLiteral.cls
+++ b/rollup/core/classes/RollupDateLiteral.cls
@@ -354,7 +354,11 @@ public without sharing abstract class RollupDateLiteral {
private class LastMonthLiteral extends RollupDateLiteral {
public LastMonthLiteral() {
this.ref = getRelativeDatetime(System.today().addMonths(-1).toStartOfMonth(), START_TIME);
- this.bound = offsetToFirstDay(getRelativeDatetime(this.ref.addMonths(1).dateGmt(), END_TIME));
+ Date relativeDate = this.ref.addMonths(1).date();
+ if (relativeDate.day() == 1) {
+ relativeDate = relativeDate.addDays(-1);
+ }
+ this.bound = offsetToFirstDay(getRelativeDatetime(relativeDate, END_TIME));
}
}
@@ -364,7 +368,11 @@ public without sharing abstract class RollupDateLiteral {
private class ThisMonthLiteral extends RollupDateLiteral {
public ThisMonthLiteral() {
this.ref = getRelativeDatetime(System.today().toStartOfMonth(), START_TIME);
- this.bound = offsetToFirstDay(getRelativeDatetime(this.ref.addMonths(1).dateGmt(), END_TIME));
+ Date relativeDate = this.ref.addMonths(1).date();
+ if (relativeDate.day() == 1) {
+ relativeDate = relativeDate.addDays(-1);
+ }
+ this.bound = offsetToFirstDay(getRelativeDatetime(relativeDate, END_TIME));
}
}
@@ -374,7 +382,11 @@ public without sharing abstract class RollupDateLiteral {
private class NextMonthLiteral extends RollupDateLiteral {
public NextMonthLiteral() {
this.ref = getRelativeDatetime(System.today().toStartOfMonth().addMonths(1), START_TIME);
- this.bound = offsetToFirstDay(getRelativeDatetime(this.ref.addMonths(1).dateGmt(), END_TIME));
+ Date relativeDate = this.ref.addMonths(1).date();
+ if (relativeDate.day() == 1) {
+ relativeDate = relativeDate.addDays(-1);
+ }
+ this.bound = offsetToFirstDay(getRelativeDatetime(relativeDate, END_TIME));
}
}
diff --git a/rollup/core/classes/RollupFlowFullRecalcDispatcher.cls b/rollup/core/classes/RollupFlowFullRecalcDispatcher.cls
index a59326bf..0fb35935 100644
--- a/rollup/core/classes/RollupFlowFullRecalcDispatcher.cls
+++ b/rollup/core/classes/RollupFlowFullRecalcDispatcher.cls
@@ -15,7 +15,7 @@ global without sharing class RollupFlowFullRecalcDispatcher {
if (String.isBlank(input.rollupDeveloperNames)) {
throw new IllegalArgumentException('Comma-separated list of Rollup__mdt DeveloperName(s) was not provided');
}
- List splitListOfApiNames = input.rollupDeveloperNames.split(',');
+ List splitListOfApiNames = input.rollupDeveloperNames.stripHtmlTags().split(',');
for (String apiName : splitListOfApiNames) {
rollupDeveloperNames.add(apiName.trim());
}
diff --git a/rollup/core/classes/RollupLogger.cls b/rollup/core/classes/RollupLogger.cls
index d5e43bdd..4423c921 100644
--- a/rollup/core/classes/RollupLogger.cls
+++ b/rollup/core/classes/RollupLogger.cls
@@ -1,7 +1,7 @@
global without sharing virtual class RollupLogger implements ILogger {
@TestVisible
// this gets updated via the pipeline as the version number gets incremented
- private static final String CURRENT_VERSION_NUMBER = 'v1.6.34';
+ private static final String CURRENT_VERSION_NUMBER = 'v1.6.35';
private static final System.LoggingLevel FALLBACK_LOGGING_LEVEL = System.LoggingLevel.DEBUG;
private static final RollupPlugin PLUGIN = new RollupPlugin();
diff --git a/rollup/core/classes/RollupRepository.cls b/rollup/core/classes/RollupRepository.cls
index 471dbe9a..18147540 100644
--- a/rollup/core/classes/RollupRepository.cls
+++ b/rollup/core/classes/RollupRepository.cls
@@ -128,7 +128,7 @@ public without sharing class RollupRepository implements RollupLogger.ToStringOb
SharingMode__c,
ShouldRunWithoutCustomSettingEnabled__c,
SplitConcatDelimiterOnCalcItem__c,
- (SELECT Id, FieldName__c, NullSortOrder__c, Ranking__c, SortOrder__c FROM RollupOrderBys__r),
+ (SELECT Id, DeveloperName, FieldName__c, NullSortOrder__c, Ranking__c, SortOrder__c FROM RollupOrderBys__r),
RollupGrouping__r.Id,
RollupGrouping__r.RollupOperation__c
FROM Rollup__mdt
@@ -149,7 +149,6 @@ public without sharing class RollupRepository implements RollupLogger.ToStringOb
meta.GroupByRowStartDelimiter__c = meta.GroupByRowStartDelimiter__c?.unescapeJava();
meta.SharingMode__c = meta.SharingMode__c ?? RollupMetaPicklists.SharingMode.SystemLevel;
meta.UltimateParentLookup__c = meta.UltimateParentLookup__r.QualifiedApiName;
- meta.RollupOrderBys__r.sort(new OrderBySorter());
}
return matchingMetadata;
diff --git a/sfdx-project.json b/sfdx-project.json
index 2ae33484..5e4f1ded 100644
--- a/sfdx-project.json
+++ b/sfdx-project.json
@@ -5,8 +5,8 @@
"package": "apex-rollup",
"path": "rollup",
"scopeProfiles": true,
- "versionName": "Fixes parentRecordIdForEmptyChildrenCollections flow case",
- "versionNumber": "1.6.34.0",
+ "versionName": "Fixes Rollup Order By sorting to always be deterministic, allows text templates in Full Recalc CMDT-driven Invocable invocable",
+ "versionNumber": "1.6.35.0",
"versionDescription": "Fast, configurable, elastically scaling custom rollup solution. Apex Invocable action, one-liner Apex trigger/CMDT-driven logic, and scheduled Apex-ready.",
"releaseNotesUrl": "https://github.com/jamessimone/apex-rollup/releases/latest",
"unpackagedMetadata": {
@@ -101,12 +101,10 @@
"Apex Rollup - Rollup Callback@0.0.3-0": "04t6g000008Sis0AAC",
"Nebula Logger - Core@4.14.4-optionally-auto-call-lightning-logger-lwc": "04t5Y0000015oRNQAY",
"apex-rollup": "0Ho6g000000TNcOCAW",
- "apex-rollup@1.6.28": "04t6g000008ObN8AAK",
- "apex-rollup@1.6.29": "04t6g000008ObNNAA0",
- "apex-rollup@1.6.30": "04t6g000008ObVhAAK",
"apex-rollup@1.6.31": "04t6g000008ObblAAC",
"apex-rollup@1.6.32": "04t6g000008ObbvAAC",
"apex-rollup@1.6.33": "04t6g000008ObeQAAS",
- "apex-rollup@1.6.34": "04t6g000008OfJfAAK"
+ "apex-rollup@1.6.34": "04t6g000008OfJfAAK",
+ "apex-rollup@1.6.35": "04t6g000008OfKiAAK"
}
}