Custom Apex allows a developer to select which records to screen and utilizes Salesforce scheduled batches to run many thousands of records in the background. It can be a flexible way for companies handling large volumes of records and avoids hitting limits with the Apex Flex Queue which can be an issue for proccessing large volumes via real time triggers.
Requires:
Batch performance is ~ 2000 Screening Cases per hour. Cases are first created, then updated with results and Audit Events. To speed up the process two or more batches can run concurrently. Please note Salesforce limits orgs to 5 apex jobs executing at the same time so care should be taken to not block other asynchronous jobs.
Batches can be started by the Scheduler or Apex script in Anonymous Apex Window within Developer Console. The maximum number of records is limited by the number of records you can collect within concurrent SOQL queries: 50,000.
The code used depends on the version of Customer Risk Screener you are using and whether you have enabled advanced setup or not. Click through for examples:
Introduced a new mapping table which holds variables such as entity type, group, name transposition. This makes the code easier to manage, just use the desired mapping Id in the objectType e.g.
item.objectType = 'a01D300000GHddSIAT'
Checks to see if an Account created in the last 24 hours already has a Screening Case record in the tr_wc1_KYC_Screening_Case__c screening object; and if not, creates a screening case record for it. Note you should customise the apex class to meet your organisation’s needs.
Name = “AccountScreeningBatchScheduler”:
global class AccountScreeningBatchScheduler implements Schedulable {
global void execute(SchedulableContext sc) {
Set<Id> accountsWithCases = new Set<Id>();
for (tr_wc1__KYC_Screening_Case__c cs: [SELECT Id, tr_wc1__Account__c FROM tr_wc1__KYC_Screening_Case__c WHERE CreatedDate > :System.now().addHours(-24) AND tr_wc1__Account__c != null]) {
accountsWithCases.add(cs.tr_wc1__Account__c);
}
List<tr_wc1.tr_automateScreeningV2.automateScreeningVars> sCaseVars = new List<tr_wc1.tr_automateScreeningV2.automateScreeningVars>();
for (Account acc : [SELECT Id FROM Account WHERE LastModifiedDate > :System.now().addHours(-24) AND Id != :accountsWithCases]) {
tr_wc1.tr_automateScreeningV2.automateScreeningVars item = new tr_wc1.tr_automateScreeningV2.automateScreeningVars();
item.objectType = 'a01D300000GHddSIAT';
item.recordId = acc.Id;
sCaseVars.add(item);
}
tr_wc1.tr_BulkCreateAndScreenCasesV2 batch = new tr_wc1.tr_BulkCreateAndScreenCasesV2(sCaseVars);
Database.executeBatch(batch, 30);
}
}
The apex can set additional variables for the case e.g. enable ongoing monitoring, or send a record to a specific group
Variable |
Comment |
Mandatory |
enableMonitoring |
Sets the Ongoing Screening Enabled flag to either TRUE or FALSE |
YES |
objectType |
Specify the object you are screening: CONTACT, LEAD or ACCOUNT, if using a custom object: CUSTOM OBJECT |
YES |
recordId |
Specify the ID of the record you are screening |
YES |
worldCheckGroupID |
The ID of the WC1 Group you wish to screen the record against. If left blank it will screen against the group setup in the Screening Setup Wizard. See Tips for how to identify a Group ID. |
*Required when screening using Custom Mapping OR if desired e.g. send accounts in country X to group 1 but all other accounts to group 2. |
enableNameTransposition |
Contacts/Individuals only. True or False. Name Transposition is useful if you do not know the word order of the name you are passing for the contact. Enabling this to true will screen the name with all variants of the word order e.g. John Doe or Doe John. Setting this may increase your hits in WorldCheck. |
NO |
screeningCaseId |
The Salesforce ID of the screening case |
*Required when updating an existing screening case, or fetching WC1 data using the ‘SkinnyCase’ process |
worldCheckOneCaseId |
The World-Check equivalent ID of the record which appears in the World-Check UI. Setting this variable tells the system which case to update. Can be found in the Screening Case object: Case ID: tr_wc1__Case_Id__c |
*Required when updating an existing screening case, or fetching WC1 data using the ‘SkinnyCase’ process |
worldCheckIneCaseSystemId |
The World-Check backend ID used by in the API integration. Setting this variable tells the system which case to update. Can be found in the Screening Case object: Case System ID: tr_wc1__Thomson_Reuters_Case_Id__c |
*Required when updating an existing screening case.
|
Navigate to a screening case record (you may need to manually create a screening case record to access the page layout if none already exist). Click the button “Get Group Ids”. A pop up appears listing all the groups and their group ids from World-Check. Copy the IDs for the Groups you wish to use.
Checks to see if a Contact created in the last 24 hours already has a Screening Case record in the tr_wc1_KYC_Screening_Case__c screening object; and if not, creates a screening case record for it. Note you should customise the apex class to meet your organisation’s needs.
Name = “ContactScreeningBatchScheduler”:
global class ContactScreeningBatchScheduler implements Schedulable {
global void execute(SchedulableContext sc) {
Set<Id> contactsWithCases = new Set<Id>();
for (tr_wc1__KYC_Screening_Case__c cs: [SELECT Id, tr_wc1__Contact__c FROM tr_wc1__KYC_Screening_Case__c WHERE CreatedDate > :System.now().addHours(-24) AND tr_wc1__Contact__c != null]) {
contactsWithCases.add(cs.tr_wc1__Contact__c);
}
List<tr_wc1.tr_automateScreening.automateScreeningVars> sCaseVars = new List<tr_wc1.tr_automateScreening.automateScreeningVars>();
for (Contact cont : [SELECT Id FROM Contact WHERE LastModifiedDate > :System.now().addHours(-24) AND Id != :contactsWithCases]) {
tr_wc1.tr_automateScreening.automateScreeningVars item = new tr_wc1.tr_automateScreening.automateScreeningVars();
item.enableMonitoring = false;
item.objectType = 'Contact';
item.recordId = cont.Id;
sCaseVars.add(item);
}
tr_wc1.tr_BulkCreateAndScreenCases batch = new tr_wc1.tr_BulkCreateAndScreenCases(sCaseVars);
Database.executeBatch(batch, 30);
}
}
Sample supporting test class:
@IsTest
private class ContactScreeningBatchSchedulerTest {
@isTest
static void testContactScreeningBatchScheduler() {
Contact cont = new Contact(LastName = 'test');
insert cont;
Test.startTest();
ContactScreeningBatchScheduler sched = new ContactScreeningBatchScheduler();
System.schedule('Daily ContactScreeningBatchScheduler', '0 0 0 * * ?', sched);
Test.stopTest();
System.assertEquals(1, [SELECT Id FROM CronJobDetail WHERE Name = 'Daily ContactScreeningBatchScheduler'].size());
}
}
Checks to see if an Account created in the last 24 hours already has a Screening Case record in the tr_wc1_KYC_Screening_Case__c screening object; and if not, creates a screening case record for it. Note you should customise the apex class to meet your organisation’s needs.
Name = “AccountScreeningBatchScheduler”
global class AccountScreeningBatchScheduler implements Schedulable {
global void execute(SchedulableContext sc) {
Set<Id> AccountWithCases = new Set<Id>();
for (tr_wc1__KYC_Screening_Case__c cs: [SELECT Id, tr_wc1__Account__c FROM tr_wc1__KYC_Screening_Case__c WHERE CreatedDate > :System.now().addHours(-24) AND tr_wc1__Account__c != null]) {
accountsWithCases.add(cs.tr_wc1__Account__c);
}
List<tr_wc1.tr_automateScreening.automateScreeningVars> sCaseVars = new List<tr_wc1.tr_automateScreening.automateScreeningVars>();
for (Account cont : [SELECT Id FROM Account WHERE LastModifiedDate > :System.now().addHours(-24) AND Id != :accountsWithCases]) {
tr_wc1.tr_automateScreening.automateScreeningVars item = new tr_wc1.tr_automateScreening.automateScreeningVars();
item.enableMonitoring = false;
item.objectType = 'Account';
item.recordId = acc.Id;
sCaseVars.add(item);
}
tr_wc1.tr_BulkCreateAndScreenCases batch = new tr_wc1.tr_BulkCreateAndScreenCases(sCaseVars);
Database.executeBatch(batch, 30);
}
}
Example supporting test class:
global class AccountScreeningBatchScheduler implements Schedulable {
global void execute(SchedulableContext sc) {
Set<Id> AccountWithCases = new Set<Id>();
for (tr_wc1__KYC_Screening_Case__c cs: [SELECT Id, tr_wc1__Account__c FROM tr_wc1__KYC_Screening_Case__c WHERE CreatedDate > :System.now().addHours(-24) AND tr_wc1__Account__c != null]) {
accountsWithCases.add(cs.tr_wc1__Account__c);
}
List<tr_wc1.tr_automateScreening.automateScreeningVars> sCaseVars = new List<tr_wc1.tr_automateScreening.automateScreeningVars>();
for (Account cont : [SELECT Id FROM Account WHERE LastModifiedDate > :System.now().addHours(-24) AND Id != :accountsWithCases]) {
tr_wc1.tr_automateScreening.automateScreeningVars item = new tr_wc1.tr_automateScreening.automateScreeningVars();
item.enableMonitoring = false;
item.objectType = 'Account';
item.recordId = acc.Id;
sCaseVars.add(item);
}
tr_wc1.tr_BulkCreateAndScreenCases batch = new tr_wc1.tr_BulkCreateAndScreenCases(sCaseVars);
Database.executeBatch(batch, 30);
}
}
Existing World-Check One Desktop customers who are migrating to Customer Risk Screener may wish to import existing case from World Check One and manage them from within Salesforce going forward. This can be supported using the "Skeleton Case" process, where Screening Cases are exported from World-Check One Desktop, the Screening Case IDs are then data loaded into the Screening Case Object. A once off Apex job can then go and fetch the data for the corresponding Screening Case IDs from World-Check. Click here for more information around the Skeleton case process.
Apex Jobs may be suitable for customers who already have many thousands of records in World-Check One that they wish to manage in Salesforce going forward.
Name: "SkeletonCaseBatchScheduler":
global class SkeletonCaseUpdateBatchScheduler implements Schedulable {
global void execute(SchedulableContext sc) {
List<tr_wc1.tr_automateScreening.automateScreeningVars> sCaseVars = new List<tr_wc1.tr_automateScreening.automateScreeningVars>();
for (tr_wc1__KYC_Screening_Case__c cs : [SELECT Id, tr_wc1__Case_Id__c, tr_wc1__Thomson_Reuters_Case_Id__c FROM tr_wc1__KYC_Screening_Case__c WHERE LastModifiedDate > :System.now().addHours(-24) AND tr_wc1__Screening_Complete__c = false AND tr_wc1__Thomson_Reuters_Group_Id__c = null AND (tr_wc1__Thomson_Reuters_Case_Id__c != null OR tr_wc1__Case_Id__c != null)]) {
tr_wc1.tr_automateScreening.automateScreeningVars item = new tr_wc1.tr_automateScreening.automateScreeningVars();
item.enableMonitoring = true;
item.objectType = 'KYC_Screening_Case';
item.recordId = cs.Id;
item.screeningCaseId = cs.Id;
item.worldCheckOneCaseId = cs.tr_wc1__Case_Id__c;
item.worldCheckOneCaseSystemId = cs.tr_wc1__Thomson_Reuters_Case_Id__c;
sCaseVars.add(item);
}
tr_wc1.tr_BulkCreateAndScreenCases batch = new tr_wc1.tr_BulkCreateAndScreenCases(sCaseVars);
Database.executeBatch(batch, 30);
}
}
The above code snippets are examples only.