You may wish to update your custom setting's during the execution of your code, to switch off validation or workflow rules.
In the below code, I have created a Schedulable Apex Class which will update the Close Date of any Opportunities whose Close Date is less than or equal to 6 days from the current date, changing the date to 20 days in the future.
I will use my Custom Setting Val_Rule_Cntrlr__c to deactivate any validation rules which would prevent me from updating the Opportunities that meet my criteria.
global class Scheduled_OppCloseDateUpdate implements Schedulable {
global void execute(SchedulableContext SC) {
updOpportunityCloseDates();
}
global void updOpportunityCloseDates() {
Id userId;
Val_Rule_Cntrlr__c setting;
Boolean validationRulesAlreadyDisabled;
List<Opportunity> processedOpps = new List<Opportunity>();
Date d;
// get running user's Id
userId = userinfo.getUserId();
// retrieve Custom Setting status, for running user
setting = Val_Rule_Cntrlr__c.getInstance(userId);
// if the setting field is false, update it to disable validation rules
if (setting.All_Opportunity_Disabled__c == false) {
setting.All_Opportunity_Disabled__c = true;
upsert setting;
}
// if the setting field was already true, there's no need to disable it
// but it shouldn't be switched to false by this class once the process has been completed
else {
validationRulesAlreadyDisabled = true;
}
// execute code to manage business process
d = system.today().addDays(6);
for(Opportunity o : [SELECT Id, CloseDate
FROM Opportunity
WHERE CloseDate <= :d
// class only updates open Opportunities
AND Probability > 0 AND Probability < 100])
{
o.CloseDate = System.today().addDays(20);
processedOpps.add(o);
}
if (processedOpps.size() > 0) {
update processedOpps;
}
// reactivate validation rules
if (validationRulesAlreadyDisabled == false) {
setting.All_Opportunity_Disabled__c = false;
upsert setting;
}
}
}
To make sure that my validation rules are being deactivated by the changes to my custom setting in my class, I have created a checkbox field Trigger_Validation_Rule__c
(which would not be visible to users or added to page layouts) & a validation rule with this criteria:
AND(
$Setup.Val_Rule_Cntrlr__c.All_Opportunity_Disabled__c = FALSE,
Trigger_Validation_Rule__c = TRUE,
/* allow the above criteria to be met while inserting the Opportunities, without triggering the rule, in the @testSetup portion of the test */
NOT(ISNEW())
)
I then set the checkbox field to true
when creating my Opportunities so that the rules criteria would be met, if the custom setting field is not edited by my code.
@isTest
private class WE_ScheduledCloseDateUpdateTest {
@testSetup
static void dataSetup() {
Profile p = [SELECT Id FROM Profile WHERE Name = 'System Administrator' LIMIT 1];
User u = new User(LastName = 'Test',Alias = 't1',Email = '[email protected]',Username = '[email protected]',ProfileId = p.Id,TimeZoneSidKey = 'America/Denver',LocaleSidKey = 'en_US',EmailEncodingKey = 'UTF-8',LanguageLocaleKey = 'en_US');
insert u;
Val_Rule_Cntrlr__c valRuleCntrlr = new Val_Rule_Cntrlr__c(SetupOwnerId = u.Id,All_Opportunity_Disabled__c = false);
upsert valRuleCntrlr;
List<Opportunity> testOpps = new List<Opportunity>();
// create the Opportunities that will be updated by the class
for(integer i = 0; i < 200; i++) {
testOpps.add(new Opportunity(
Name = 'Test Opp Update' + i,
OwnerId = u.Id,
StageName = 'Prospecting',
CloseDate = date.today().addDays(1),
Amount = 100,
// set checkbox field to true, to trigger validation rules if they've not been deactivated by class
Trigger_Validation_Rule__c = true));
}
// create the Opportunities that won't be updated by the class
for(integer i = 0; i < 200; i++) {
testOpps.add(new Opportunity(
Name = 'Test Opp Skip' + i,
OwnerId = u.Id,
StageName = 'Prospecting',
CloseDate = date.today().addDays(15),
Amount = 100,
Trigger_Validation_Rule__c = true));
}
insert testOpps;
}
// code required to test a scheduled class, see https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_scheduler.htm for more details
public static String CRON_EXP = '0 0 0 15 3 ? 2022';
static testmethod void testCloseDateUpdates() {
// execute scheduled class
Test.startTest();
String jobId = System.schedule('ScheduleApexClassTest',
CRON_EXP,
new Scheduled_OppCloseDateUpdate());
CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered, NextFireTime
FROM CronTrigger
WHERE id = :jobId];
System.assertEquals(CRON_EXP, ct.CronExpression);
System.assertEquals(0, ct.TimesTriggered);
System.assertEquals('2022-03-15 00:00:00', String.valueOf(ct.NextFireTime));
Test.stopTest();
// test results
Integer updateCount = 0;
Integer skipCount = 0;
List <Opportunity> opportunitys = [SELECT Id, Name, CloseDate FROM Opportunity];
for(Opportunity o : opportunitys) {
if (o.Name.contains('Update') &&
updateCount == 0)
{
System.assertEquals(date.today().addDays(20), o.CloseDate, 'Opportunity\'s Close Date should have been updated as it was less than 7 days away');
updateCount = 1;
}
if (o.Name.contains('Skip') &&
skipCount == 0)
{
System.assertEquals(date.today().addDays(15), o.CloseDate, 'Opportunity should not have been updated as it\'s Close Date is more than 7 days away');
skipCount = 1;
}
}
// check that both lists of Opportunities have been tested
System.assertEquals(2, updateCount + skipCount, 'Count should be 2 once all assertions have been executed');
}
// check that the class does not change the custom setting's field to false, if it was true before class was executed
static testmethod void testSettingUpdates() {
User u = [SELECT Id FROM User WHERE UserName = '[email protected]'];
// switch the custom setting field to true before the scheduled job executes
Val_Rule_Cntrlr__c setting;
setting = Val_Rule_Cntrlr__c.getInstance(u.Id);
setting.All_Opportunity_Disabled__c = true;
upsert setting;
System.runAs(u) {
Test.startTest();
String jobId = System.schedule('ScheduleApexClassTest',
CRON_EXP,
new Scheduled_OppCloseDateUpdate());
CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered, NextFireTime
FROM CronTrigger
WHERE id = :jobId];
System.assertEquals(CRON_EXP, ct.CronExpression);
System.assertEquals(0, ct.TimesTriggered);
System.assertEquals('2022-03-15 00:00:00', String.valueOf(ct.NextFireTime));
Test.stopTest();
}
setting = Val_Rule_Cntrlr__c.getInstance(u.Id);
// check that the class did not change the All_Opportunity_Disabled__c field to false
System.assertEquals(true, setting.All_Opportunity_Disabled__c);
}
}