Skip to content

Commit 9e4c27c

Browse files
authored
V0.0.2 - JavaDoc comments & Single Record Input for Flow (#2)
* Started adding in javadoc comments in a few places where it will help Apex consumers of the code. Removed a few lingering references to apex-rollup from copied files. Added definitionFile property to sfdx-project.json, though packaging still fails locally when attempting to revert AbstractCacheRepo to non-safeguarded version * Wrapping some README text that was overflowing * Finalizing v0.0.2 changes by adding single record input variable as per @rygramer's suggestion
1 parent f6c76e0 commit 9e4c27c

File tree

11 files changed

+74
-30
lines changed

11 files changed

+74
-30
lines changed

README.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55

66
## Deployment
77

8-
<a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008SjNvAAK">
8+
<a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008SjOFAA0">
99
<img alt="Deploy to Salesforce"
1010
src="./media/deploy-package-to-prod.png">
1111
</a>
1212

13-
<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008SjNvAAK">
13+
<a href="https://test.salesforce.com/packaging/installPackage.apexp?p0=04t6g000008SjOFAA0">
1414
<img alt="Deploy to Salesforce Sandbox"
1515
src="./media/deploy-package-to-sandbox.png">
1616
</a>
@@ -44,7 +44,8 @@ And then the configuration for the action:
4444
- `Owner Field API Name - defaults to OwnerId` (optional) - which field are you looking to assign to? Not all objects have `OwnerId` as a field (the detail side of M/D relationships, for instance). Use the field's API Name for these cases.
4545
- `Query Id Field - defaults to Id if not supplied` (optional) - used in conjunction with the `Query To Retrieve Possible Assignees` property, below. If you are using the round robin assigner to assign lookup fields _other_ than `OwnerId`, this allows you to override which field is pulled off of the records that the `Query To Retrieve Possible Assignees` returns.
4646
- `Query To Retrieve Possible Assignees` (optional) - either this or `Alternative to query ...` must be provided! This query will pull back records - like Users - and grab their `Id` field (or the field stipulated using the `Query Id Field ...` property) that should be included in the "ownership pool" for the given round robin.
47-
- `Records To Round Robin` (optional, but should always be supplied) - set this equal to a collection variable that is either the output of a `Get Records` call, contains `$Record` in a Record-Triggered flow, etc ...
47+
- `Records to round robin - either this or single record is required` (optional) - set this equal to a collection variable that is either the output of a `Get Records` call, contains `$Record` in a Record-Triggered flow, etc ...
48+
- `Single record to round robin - either this or records to round robin is required` (optional) - for Record-Triggered Flows, skip assigning `$Record` to a collection variable and just pass it directly using this input property!
4849
- `Update records - defaults to false` (optional) - by default, the collection supplied via the `Records To Round Robin` property aren't updated; set this to `{!$GlobalConstant.True}` to have the action update your records with their newly assigned owners
4950

5051
## Round Robin Assignment From Apex
@@ -57,8 +58,10 @@ Here are a few ways that you can perform assignments:
5758
- You can call use the bundled `QueryAssigner`:
5859

5960
```java
60-
// in a Trigger/ trigger handler class
61-
RoundRobinAssigner.IAssignmentRepo queryRepo = new QueryAssigner('SELECT Id FROM User WHERE Some_Condition__c = true', 'Id');
61+
// in a Trigger / trigger handler class
62+
RoundRobinAssigner.IAssignmentRepo queryRepo = new QueryAssigner(
63+
'SELECT Id FROM User WHERE Some_Condition__c = true', 'Id'
64+
);
6265
RoundRobinAssigner.Details assignmentDetails = new RoundRobinAssigner.Details();
6366
assignmentDetails.assignmentType = 'this is the cache key';
6467
new RoundRobinAssigner(queryRepo, assignmentDetails).assignOwners(someListOfSObjectsToBeAssigned);

config/pmd-ruleset.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0"?>
2-
<ruleset name="Apex Rollup Rules"
2+
<ruleset name="Round Robin Rules"
33
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
44
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
55
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">

core/classes/AbstractCacheRepo.cls

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ public abstract class AbstractCacheRepo implements Cache.CacheBuilder {
77
this.getPartition()?.put(this.getCacheKey(), cachedItem);
88
}
99

10+
/**
11+
* We want to prevent downstream consumers from overriding `toString()`
12+
* because otherwise they can break the way `getCacheBuilder()` works
13+
* within this class
14+
*/
15+
public override String toString() {
16+
return super.toString();
17+
}
18+
1019
protected abstract String getCachePartitionName();
1120
protected abstract String getCacheKey();
1221
protected abstract Object populateCache();
@@ -29,8 +38,8 @@ public abstract class AbstractCacheRepo implements Cache.CacheBuilder {
2938
return Type.forName(className);
3039
}
3140

32-
@SuppressWarnings('PMD.EmptyCatchBlock')
33-
private Cache.OrgPartition getPartition() {
41+
@SuppressWarnings('PMD.EmptyCatchBlock')
42+
private Cache.OrgPartition getPartition() {
3443
Cache.OrgPartition partition;
3544
try {
3645
partition = Cache.Org.getPartition(this.getCachePartitionName());

core/classes/FlowRoundRobinAssigner.cls

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,18 @@ global without sharing class FlowRoundRobinAssigner {
1616
global String queryIdField = 'Id';
1717
@InvocableVariable(label='Owner Field API Name - defaults to OwnerId')
1818
global String ownerFieldApiName = 'OwnerId';
19-
@InvocableVariable(label='Records to round robin')
19+
@InvocableVariable(label='Records to round robin - either this or single record is required')
2020
global List<SObject> recordsToRoundRobin = new List<SObject>();
21+
@InvocableVariable(label='Single record to round robin - either this or records to round robin is required')
22+
global SObject recordToRoundRobin;
2123
@InvocableVariable(label='Update records - defaults to false')
2224
global Boolean updateRecords = false;
2325
}
2426

2527
@InvocableMethod(category='Round Robin' label='Round robin records')
2628
global static void assign(List<FlowInput> flowInputs) {
2729
for (FlowInput input : flowInputs) {
28-
if (input.recordsToRoundRobin?.isEmpty() == false) {
30+
if (input.recordsToRoundRobin?.isEmpty() == false || input.recordToRoundRobin != null) {
2931
SELF.trackAssignedIds(input);
3032
SELF.roundRobin(input);
3133
}
@@ -49,6 +51,9 @@ global without sharing class FlowRoundRobinAssigner {
4951
'Query To Retrieve Possible Assignees or API name of class implementing RoundRobinAssigner.IAssignment repo is required!'
5052
);
5153
}
54+
if (input.recordsToRoundRobin?.isEmpty() != false && input.recordToRoundRobin != null) {
55+
input.recordsToRoundRobin = new List<SObject>{ input.recordToRoundRobin };
56+
}
5257
}
5358

5459
private void trackAssignedIds(FlowInput input) {

core/classes/FlowRoundRobinAssignerTests.cls

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ private class FlowRoundRobinAssignerTests {
3838
Exception ex;
3939
try {
4040
FlowRoundRobinAssigner.assign(new List<FlowRoundRobinAssigner.FlowInput>{ input });
41-
} catch(System.IllegalArgumentException e) {
41+
} catch (System.IllegalArgumentException e) {
4242
ex = e;
4343
}
4444

@@ -54,11 +54,22 @@ private class FlowRoundRobinAssignerTests {
5454
FlowRoundRobinAssigner.FlowInput input = new FlowRoundRobinAssigner.FlowInput();
5555
input.updateRecords = true;
5656
input.recordsToRoundRobin = new List<ContactPointAddress>{ cpa };
57-
input.queryToRetrieveAssignees = 'SELECT Id FROM User WHERE Id = \'' + UserInfo.getUserId() + '\'';
57+
input.queryToRetrieveAssignees = 'SELECT Id FROM User WHERE Id = \'' + UserInfo.getUserId() + '\'';
5858

5959
FlowRoundRobinAssigner.assign(new List<FlowRoundRobinAssigner.FlowInput>{ input });
6060

6161
System.assertEquals(true, FlowRoundRobinAssigner.hasBeenUpdated);
6262
System.assertEquals(UserInfo.getUserId(), cpa.OwnerId);
6363
}
64+
65+
@IsTest
66+
static void singleRecordRoundRobins() {
67+
FlowRoundRobinAssigner.FlowInput input = new FlowRoundRobinAssigner.FlowInput();
68+
input.recordToRoundRobin = new ContactPointAddress();
69+
input.queryToRetrieveAssignees = 'SELECT Id FROM User WHERE Id = \'' + UserInfo.getUserId() + '\'';
70+
71+
FlowRoundRobinAssigner.assign(new List<FlowRoundRobinAssigner.FlowInput>{ input });
72+
73+
System.assertEquals(UserInfo.getUserId(), input.recordToRoundRobin.get('OwnerId'));
74+
}
6475
}

core/classes/RoundRobinAssigner.cls

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,21 @@ public without sharing class RoundRobinAssigner implements IThreadSafeCacheVisit
66
private static final Integer SENTINEL_INDEX = -1;
77
private static final String OWNER_ID = 'OwnerId';
88

9+
/**
10+
* Implement this interface to define an assignment "pool"
11+
* for round robin assigning owners to records
12+
*/
913
public interface IAssignmentRepo {
1014
List<Id> getAssignmentIds(String assignmentType);
1115
}
1216

17+
/**
18+
* Data object designed to encapsulate one to two properties associated with assignment
19+
* - assignmentType: also used as the cache key, this property is configurable.
20+
* In Flow, defaults to `SObjectType.OwnerFieldName` (e.g. `Lead.OwnerId`)
21+
* - ownerField: (optional), defaults to `OwnerId`. IT's not necessary for this field to be part of the cache key,
22+
* but it might be a nice way to differentiate entries in the cache in a consistent way
23+
*/
1324
public class Details {
1425
public String assignmentType { get; set; }
1526
public String ownerField {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ApexTestSuite xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<testClassName>FlowRoundRobinAssignerTests</testClassName>
4+
<testClassName>RoundRobinAssignerTests</testClassName>
5+
<testClassName>RoundRobinFlowIntegrationTests</testClassName>
6+
<testClassName>RoundRobinRepositoryTests</testClassName>
7+
</ApexTestSuite>

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "salesforce-round-robin",
3-
"version": "0.0.1",
3+
"version": "0.0.2",
44
"description": "Round robin records in Salesforce (SFDC) using Flow or Apex. Performant, fair, fast assignment with configurable user pools",
55
"repository": {
66
"type": "git",
@@ -26,7 +26,7 @@
2626
"prettier": "prettier",
2727
"scan": "sfdx scanner:run --pmdconfig config/pmd-ruleset.xml --target . --engine pmd --severity-threshold 3",
2828
"test": "npm run test:apex",
29-
"test:apex": "sfdx force:apex:test:run -w 10",
29+
"test:apex": "sfdx force:apex:test:run -s RoundRobinTestSuite -w 10",
3030
"test:lwc": "echo No LWCs so far!"
3131
}
3232
}

scripts/build-and-promote-package.ps1

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,13 @@ function Get-Current-Git-Branch() {
1313

1414
function Start-Package-Promotion {
1515
Write-Debug "Beginning promote script"
16-
17-
$allReadmes = Get-ChildItem -Exclude node_modules, .sfdx, tests | Get-ChildItem -Filter README.md -Recurse
18-
foreach ($readme in $allReadmes) {
19-
$readmePackageIdResults = (Select-String -Path $readme 'https:\/\/login.salesforce.com\/packaging\/installPackage.apexp\?p0=.{0,18}')
20-
if ($readmePackageIdResults.Matches.Length -gt 0) {
21-
$packageIdSplit = $readmePackageIdResults.Matches[0].Value.Split("=")
22-
if ($packageIdSplit.Length -eq 2) {
23-
$packageId = $packageIdSplit[1]
24-
Write-Debug "Promoting $packageId from $readme"
25-
npx sfdx force:package:version:promote -p $packageId -n
26-
}
16+
$readmePackageIdResults = (Select-String -Path "README.md" 'https:\/\/login.salesforce.com\/packaging\/installPackage.apexp\?p0=.{0,18}')
17+
if ($readmePackageIdResults.Matches.Length -gt 0) {
18+
$packageIdSplit = $readmePackageIdResults.Matches[0].Value.Split("=")
19+
if ($packageIdSplit.Length -eq 2) {
20+
$packageId = $packageIdSplit[1]
21+
Write-Debug "Promoting $packageId from $readme"
22+
npx sfdx force:package:version:promote -p $packageId -n
2723
}
2824
}
2925
Write-Debug "Finished package promotion!"

scripts/test.ps1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ if($shouldDeployToSandbox) {
7373
try {
7474
# Deploy
7575
Write-Debug "Deploying source to sandbox ..."
76-
npx sfdx force:source:deploy -p rollup
77-
npx sfdx force:source:deploy -p extra-tests
76+
npx sfdx force:source:deploy -p core
77+
npx sfdx force:source:deploy -p integration-tests
7878
Start-Tests
7979
} catch {
8080
throw 'Error deploying to sandbox!'

0 commit comments

Comments
 (0)