• Sierra VP
  • NEWBIE
  • 10 Points
  • Member since 2019

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 1
    Questions
  • 3
    Replies

I'm new to developing and trying to determine if I will get errors thrown in my batch apex code. The purpose is to: upon deactivation of a user (trigger, which I understand isn't best practice but don't know another way the batch can be automatically started w/o checking for deactivated users every night), all of the leads of deactivated user are queried to change the OwnerId to a catchall user. The trick is that one user may have as many as 200,000 leads that need to be updated, hence why I am using batch apex. Two questions:

1. How many batch jobs will be activated with each deactivated user? (I think the answer is one?)

2. Will the batch job be sent to the Flex Queue as 'holding' and then to active, giving the org 105 possible batch jobs to be held/processed at once before throwing errors, or will it bypass Flex Queue, thereby limiting the org to only 5 batch jobs at a time?

I hope my questions make sense, and I appreciate any help. I have spent many hours researching this as a newbie. In case it's relevant, my code is below:

Trigger:

trigger BatchUpdateTrigger2 on User (after update)  {

//Map will keep deactivated users and their Id's, to be used later in batch Apex
	 Map<id, User> DeactivatedUsers = new Map<id, User>();
//Check all users in trigger, first if the IsActive button has been newly changed and if it now says that the user is not active    
for (Integer i=0;i<Trigger.new.size();i++) {
    
if (Trigger.new[i].IsActive!=Trigger.old[i].IsActive &&
   Trigger.new[i].IsActive == false) {
	DeactivatedUsers.put(Trigger.new[i].Id, Trigger.new[i]);
   }
}
// Make sure that there are users to be processed
if (DeactivatedUsers.size() > 0) {

            BatchUpdateLeads objBatchUpdateLeads=new BatchUpdateLeads(DeactivatedUsers);
            Database.executeBatch(objBatchUpdateLeads);
}
}


Batch Apex Class:

global class BatchUpdateLeads implements Database.Batchable<SObject> {
   
        //Save a public variable to hard-code the catchall user that will become lead owner
  	public Id GenericUserId = '0054P000009pLkrQAE';
    
    //map of userid - user that retrieves deactivated user(s) from previous trigger
    Map<Id, User> DeactivatedUsersMap = new Map<Id, User>();
    
    global BatchUpdateLeads(Map<Id, User> DeactivatedUsers) {
    DeactivatedUsersMap = DeactivatedUsers;
    }
    
//Search for the leads whose OwnerId is the deactivated user(s)
    global Database.QueryLocator start(Database.BatchableContext BC) {
    return DataBase.getQueryLocator([SELECT Id, OwnerId FROM Lead WHERE OwnerId IN : DeactivatedUsersMap.keySet()]);
    }
    
    //For leads whose owner was deactivated, change OwnerId to the catchall user
    global void execute(Database.BatchableContext BC, List<sObject> scope){
              List<Lead> leads = (List<lead>)scope;
                for (Lead l: leads){
                    l.OwnerId = GenericUserId;}
        
//Check that there are leads to be updated, then update
            if (leads.size() > 0){
              update leads;
            }
    	}
    global void finish(Database.BatchableContext BC) {
        
    //Send an email to system admin after the batch completes (fill in email)
    Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
    String[] toAddresses = new String[] {'xxxxxxx@gmail.com'};
    mail.setToAddresses(toAddresses);
    mail.setSubject('Apex Batch Job is done');
    mail.setPlainTextBody('The Batch Apex Job Processed Successfully');
    Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}

I'm new to developing and trying to determine if I will get errors thrown in my batch apex code. The purpose is to: upon deactivation of a user (trigger, which I understand isn't best practice but don't know another way the batch can be automatically started w/o checking for deactivated users every night), all of the leads of deactivated user are queried to change the OwnerId to a catchall user. The trick is that one user may have as many as 200,000 leads that need to be updated, hence why I am using batch apex. Two questions:

1. How many batch jobs will be activated with each deactivated user? (I think the answer is one?)

2. Will the batch job be sent to the Flex Queue as 'holding' and then to active, giving the org 105 possible batch jobs to be held/processed at once before throwing errors, or will it bypass Flex Queue, thereby limiting the org to only 5 batch jobs at a time?

I hope my questions make sense, and I appreciate any help. I have spent many hours researching this as a newbie. In case it's relevant, my code is below:

Trigger:

trigger BatchUpdateTrigger2 on User (after update)  {

//Map will keep deactivated users and their Id's, to be used later in batch Apex
	 Map<id, User> DeactivatedUsers = new Map<id, User>();
//Check all users in trigger, first if the IsActive button has been newly changed and if it now says that the user is not active    
for (Integer i=0;i<Trigger.new.size();i++) {
    
if (Trigger.new[i].IsActive!=Trigger.old[i].IsActive &&
   Trigger.new[i].IsActive == false) {
	DeactivatedUsers.put(Trigger.new[i].Id, Trigger.new[i]);
   }
}
// Make sure that there are users to be processed
if (DeactivatedUsers.size() > 0) {

            BatchUpdateLeads objBatchUpdateLeads=new BatchUpdateLeads(DeactivatedUsers);
            Database.executeBatch(objBatchUpdateLeads);
}
}


Batch Apex Class:

global class BatchUpdateLeads implements Database.Batchable<SObject> {
   
        //Save a public variable to hard-code the catchall user that will become lead owner
  	public Id GenericUserId = '0054P000009pLkrQAE';
    
    //map of userid - user that retrieves deactivated user(s) from previous trigger
    Map<Id, User> DeactivatedUsersMap = new Map<Id, User>();
    
    global BatchUpdateLeads(Map<Id, User> DeactivatedUsers) {
    DeactivatedUsersMap = DeactivatedUsers;
    }
    
//Search for the leads whose OwnerId is the deactivated user(s)
    global Database.QueryLocator start(Database.BatchableContext BC) {
    return DataBase.getQueryLocator([SELECT Id, OwnerId FROM Lead WHERE OwnerId IN : DeactivatedUsersMap.keySet()]);
    }
    
    //For leads whose owner was deactivated, change OwnerId to the catchall user
    global void execute(Database.BatchableContext BC, List<sObject> scope){
              List<Lead> leads = (List<lead>)scope;
                for (Lead l: leads){
                    l.OwnerId = GenericUserId;}
        
//Check that there are leads to be updated, then update
            if (leads.size() > 0){
              update leads;
            }
    	}
    global void finish(Database.BatchableContext BC) {
        
    //Send an email to system admin after the batch completes (fill in email)
    Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
    String[] toAddresses = new String[] {'xxxxxxx@gmail.com'};
    mail.setToAddresses(toAddresses);
    mail.setSubject('Apex Batch Job is done');
    mail.setPlainTextBody('The Batch Apex Job Processed Successfully');
    Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}
Hello developer heroes!

I'm working through the Apex modules on Trailhead and can't seem to get past this one: https://developer.salesforce.com/en/trailhead/force_com_programmatic_beginner/apex_triggers/apex_triggers_bulk.

Hopefully this doesn't read like a 'please complete the course for me' kinda post, but I have written a trigger that I believe meets the criteria but it isn't passing the check, so I wanted to seek the guidance of the experts.

The challenge is to do this:

Create an Apex trigger for Opportunity that adds a task to any opportunity set to 'Closed Won'.

To complete this challenge, you need to add a trigger for Opportunity. The trigger will add a task to any opportunity inserted or updated with the stage of 'Closed Won'. The task's subject must be 'Follow Up Test Task'.The Apex trigger must be called 'ClosedOpportunityTrigger'

- With 'ClosedOpportunityTrigger' active, if an opportunity is inserted or updated with a stage of 'Closed Won', it will have a task created with the subject 'Follow Up Test Task'.
- To associate the task with the opportunity, fill the 'WhatId' field with the opportunity ID.
- This challenge specifically tests 200 records in one operation.


And here is the trigger I have come up with, which compiles OK and stands up to a manual (though admittedly unbulkified) test:
trigger ClosedOpportunityTrigger on Opportunity (after insert, after update) {

    List<Task> taskList = new List<Task>();
    
    for (Opportunity opp : [SELECT Id, StageName FROM Opportunity WHERE StageName = 'Closed Won' AND Id IN :Trigger.new]){
                    
            taskList.add(new Task(Subject = 'Follow Up Test Task',
                                  WhatId = opp.Id));
       
    }

    if(taskList.size()>0){
        
        insert taskList;
        
    }
    
}
I have tried replacing the SOQL with a straightforward 'for (Opportunity opp : Trigger.new)' and having the taskList.add inside an IF that checks for Closed Won - no luck. I also thought about checking to see if the stage was being changed to Closed Won, rather than the trigger firing on every edit, but I don't think this is what the module is asking for.

Where do you think I'm going wrong?

Huge thanks in advance!