2

I'm pretty new to apex. I did some java and other various languages in school, but this has been my first real project since then.

The objective: Provide the capablity to rotate leads in a Load-Balanced style, among reps in a given territory. Further, check if the reps are inside or outside reps, and assign accordingly.

I have figured out how to do this on a single-lead basis; putting the button on the lead page itself. What I would like to do, is be able to do this from a list view, checking a handful of leads, and clicking the "Rotate Leads" button, and having all of the selected leads processed in the same manner.

I currently have two custom objects set up: Lead Rotator User and Rotated Lead

I have a few custom fields on each, one being Leads_Rotated_since_last_clear__c which allows me to load-balance and rotate.

The Apex code I have is:

global class leadRotator{

//General Process
//1--Person pushes Lead Rotator Button
//2--Needed from Lead: Territory, lead object/ID
//3--Query all Lead Rotator Users in the territory of the lead taking Outside rep flag into consideration
//4--Pull in the user/id and lead rotator user id of the rep with the lowest leads rotated to them since the last time it was cleared
//5--Create entry into Rotated Leads table using current user for "rotated by", user from comment 4 for "rotated to",
//6--using lead from comment 2 for the lead reference, rotated date = today()
//7--Increment the Leads_Rotated_since_last_clear__c field on the lead rotator user found in comment 4
//8--Assign the lead to the rep identified in comment 4


webservice static void rotateLead(list<id> leadsToRotate){
  //declare variables
  string strTerritoryFromLead;
     string strLeadRotatorUser;
     lead leadFromID;
     boolean boolOutsideRepFromLead;
     string strUserName = Userinfo.getFirstName() + ' ' + userinfo.getLastName();
     Lead_Rotator_Users__c LeadRotatorUser;

     //loop through the leads in the list returned by the method
  for (id l :leadsToRotate){

   //Take ID from page, and assign to a lead variable
   leadFromID = [select ID,Territory__c,F1000_Headquarters_lead__c from lead where id=:l];

   //assign varables values from the lead
   strTerritoryFromLead = leadFromID.Territory__c;
   boolOutsideRepFromLead = leadFromID.F1000_Headquarters_lead__c;

   system.debug('territory variable: '+ strTerritoryFromLead);
   system.debug('f1000 flag on lead: ' + boolOutsideRepFromLead);
   system.debug('lead ID: ' + leadFromID.id);
   system.debug('strUserName: ' + strUserName);


   LeadRotatorUser =
   [ 
   //Query to determine next person to rotate to
   SELECT Id,Name,Outside_Rep__c,Territory__c, Leads_Rotated_since_last_clear__c,Rep_Name__c FROM Lead_Rotator_Users__c
   WHERE Outside_Rep__c = :boolOutsideRepFromLead AND Territory__c = :strTerritoryFromLEad
   ORDER BY Leads_Rotated_since_last_clear__c ASC NULLS FIRST LIMIT 1
   ];

   Rotated_Lead__c rl = new Rotated_Lead__c(
    Lead__c =leadFromID.id,
    Lead_Rotated_by__c = strUserName,
    Rep_Rotated_To_ID__c = LeadRotatorUser.id
    );//Create lead to insert into the Rotated Lead Table


   insert rl;//insert to the rotated lead table
   if(Leadrotatoruser.Leads_Rotated_since_last_clear__c == null){
   Leadrotatoruser.Leads_Rotated_since_last_clear__c = 1;
   }else{
   Leadrotatoruser.Leads_Rotated_since_last_clear__c ++; //increment the counter on the lead rotator user
   }
   update LeadRotatorUser; //update the lead rotator user

   leadfromID.ownerID = LeadRotatorUser.Rep_Name__c;
   update leadfromID;

  }//end loop through leads in the list returned by the method

}//rotateLead Method end
} //End Class

The button I use on the lead page:

{!REQUIRESCRIPT("/soap/ajax/15.0/connection.js")}
{!REQUIRESCRIPT("/soap/ajax/15.0/apex.js")}

var r = confirm("Are you sure want to rotate the lead?");
if(r == true)
{
sforce.apex.execute("leadRotator","rotateLead",{leadsToRotate:"{! Lead.Id }"});
location.reload(true);
}

When I use the same code for the list-view button, I get an "Invalid ID" error.

I'm also a little worried about hitting query limits running this way, but I don't know a way around that... It should work just fine on a detail page.

Also, I need to write a method that will go through and reset the number of leads that have been rotated to each rep with a button on the Lead_Rotator_users object as well. I'm not sure how to pass the various records that are checked in a list view to a method in apex.

Any Ideas?

1 Answer 1

1

Here is an example of a "List Button" that works in a list view (of Claim__c custom objects); it is the Salesforce provided function GETRECORDIDS that does the work of picking up the ids from the selected rows and producing a JavaScript array:

{!REQUIRESCRIPT('/soap/ajax/25.0/connection.js')}
{!REQUIRESCRIPT('/soap/ajax/25.0/apex.js')}

var ids = {!GETRECORDIDS($ObjectType.Claim__c)};
if (ids.length > 0) {
    var result = sforce.apex.execute('ClaimActions', 'updateSummary', {claimIds: ids});
    if ('success' == result) {
        // See the changes
        window.location.reload();
    } else {
        // See the error message
        alert(result);
    }
} else {
    alert('Select at least one Claim first using the checkboxes');
}

and this is the signature of the Apex it calls:

global with sharing class ClaimActions {
    WebService static String updateSummary(Id[] claimIds) {
        ....
        return 'success';
    }
}

So it is normal to have slightly different button code (hopefully calling the same Apex Webservice) for the two types of buttons. This "List Button" approach will work for both the cases where you want to select items from a list view, be they Lead objects or Lead_Rotator_Users__c object lists.

You are right to be concerned about governor limits in your Apex as you are doing several queries and updates per Lead Id. So as well as perhaps being sluggish for your users, when a large number of Lead Ids are selected your code will blow up with a governor limit exception.

The general solution is to work with sets of data rather than individual items. This means you perform the same number of queries and updates no matter how many Ids are involved. So in your first query you might do this (and not inside a for loop):

Lead[] leads = [
        select Id, Territory__c, F1000_Headquarters_Lead__c
        from Lead
        where Id in :leadsToRotate
        ];

and when you do an update you do it on a list of objects you have built rather than one at a time.

Unfortunately this "bulkification" can sometimes be challenging to create depending on the relationships between objects. (Google "trigger bulkification" or similar for various examples and strategies.) So you may wish to start without it to get your code working. Unit tests are then a great help when you refactor to add the bulkification.

1
  • "GETRECORDIDS that does the work of picking up the ids from the selected rows and producing a JavaScript array:"..This solved my problem also :)
    – Varun
    Oct 25, 2014 at 1:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .