function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
TinkuTinku 

Re-assigning the Account Owner

I have a requirement, where:

 

Based on the 'opportunity' stage and 'account' billing state, i have to reassign the account owners to some specific users.

 

I am trying to write a trigger for this. When i am assigning account.owner to a user, it gives out an 'Illegal Assignment error". Can anyone please help me with this problem.

 

Here is the code:

 

trigger AccountAssignment on Opportunity (after insert, after update)
{
  Account act;
 
  for(Opportunity Opp : trigger.New[0])
  {
     if((opp.StageName=='Contract')&& (act.BillingState == 'ME'||
     act.BillingState == 'NH'||act.BillingState == 'VT'||act.BillingState == 'NY'||act.BillingState == 'PA'||act.BillingState == 'DC'||act.BillingState == 'MD'
     ||act.BillingState == 'DE'||act.BillingState == 'NJ'||act.BillingState == 'CT'||act.BillingState == 'RI'||act.BillingState == 'MA'))
     {
           act.owner = 'Holly Esposito'; // error is at this line : Illegal assignment from String to SOBJECT:User
           
     }
   }
     
  update Act;
   
}

David81David81

The field you want to change on the Account is actually OwnerId so you'll need to get the Id for the User you want to set as the owner.

 

We've done something similar where we set up a Custom Setting that had all the states listed an a Rep Territory number. On the User records we set a Territory Number field to coincide with the territory they should own. So in our code we query the user table to get the users and their terriroty numbers and add these to a map indexed by the territory number. Then we can use the custom setting to look up the appropriate territory based on state and assign the proper user.

 

Let me know if that doesn't make sense and I can explain further if need be.

TinkuTinku

Thanks for the suggestion.

 

I took the ID from the user, and assigned that ID to the act.OwnerID

 

 for(Opportunity Opp : trigger.New[0]) // at this line, Compile Error: Loop must iterate over a collection type: SOBJECT:Opportunity
  {
     if((opp.StageName=='Contract')&&(opp.Number_of_Recruiters__c=='5-9')&& (act.BillingState == 'ME'||
     act.BillingState == 'NH'||act.BillingState == 'VT'||act.BillingState == 'NY'||act.BillingState == 'PA'||act.BillingState == 'DC'||act.BillingState == 'MD'
     ||act.BillingState == 'DE'||act.BillingState == 'NJ'||act.BillingState == 'CT'||act.BillingState == 'RI'||act.BillingState == 'MA'))
     {
                    
          act.ownerID ='u=00560000000mpRk';
               }
   }
     
   update act;

}

 

I should tell you that am fairly new to SFDC and this is actually my first trigger.

David81David81

Sorry, I should have caught that before.

 

trigger.New[0] returns only the first item in the trigger.new List. Take off the [0] to get the full list.

 

As a general rule, you don't want to hard code IDs in triggers. You really should be getting it from the User table or at least a Custom Setting. If you do hard code the ID, make sure to take out the 'u='

TinkuTinku

Thanks for the suggestion:

 

I removed the array from the trigger.New and the code is saved now. Testing it and will post my queries if i hit any issues.

 

 

 

 

TinkuTinku

When i am creating an opportunity with the given criterias and while saving it, this error comes up:

 

AccountAssignment: execution of AfterUpdate caused by: System.NullPointerException: Attempt to de-reference a null object: Trigger.AccountAssignment:

 

The error is for the below line of code

 

act.ownerID ='u=00560000000mpRk';

 

It is pointint at some null value.

 

Is it because my trigger is on opportunity and i am trying to update ownerId on Account?

 

Any suggestions please.

TinkuTinku

The updated code based on some feedbacks is this:

 

 

trigger AccountAssignment on Opportunity (after insert,after update) 
{
    
  //List<id> OwnerID = New List<id>();
  Account act;
  
  for(Opportunity opp : trigger.New)
  { 
Line 9: if((opp.StageName=='Contract') &&(opp.Number_of_Recruiters__c=='5-9')&& (act.BillingState == 'ME'||
act.BillingState == 'NH'||act.BillingState == 'VT'||act.BillingState == 'NY'||act.BillingState == 'PA'||act.BillingState == 'DC'||act.BillingState == 'MD'
     ||act.BillingState == 'DE'||act.BillingState == 'NJ'||act.BillingState == 'CT'||act.BillingState == 'RI'||act.BillingState == 'MA'))
                   {
          act.ownerID =[select ID from User where name = 'Holly Esposito'].id;
          
          system.debug(opp.StageName);
          system.debug(act.BillingState);
          }
   }
     
}


Now the code is saving. But when i create a Opportunity and give the
conditions as described in the trigger, it gives this error:


unexpected exception: AccountAssignment: execution of AfterUpdate caused by: System.NullPointerException: Attempt to de-reference a null object: Trigger.AccountAssignment: line 9


I think the error is because i have not done the cross-object reference between opportunity and account properly in the trigger. Can anyone help me out with the cross-object reference in triggers please.

The opportunity object does not have the 'Billing State' field. This field is available only in Account. That is why i need a way to refer that into opportunity.

Any ideas and suggestions are welcome.
Thank you
David81David81

I probably should have caught that before, sorry. There's a good bit that needs changed to get this to work efficiently. Let me ask this, are there other users that need to be used as owners of accounts if they are in different states?

TinkuTinku

yes. There are four different categories.

States from South assign to User1

States from North assign to User2

States from East assign to User3

States from West assign to User4

 

TinkuTinku

The updated trigger:

 

trigger AccountAssignment on Opportunity (after insert,after update)
{

    ID ID1;

    List<Account> acct ;

      for(Opportunity opp : trigger.New)

       {

             if(opp!=null)

        {
 
             ID1 = opp.AccountId;

             acct = [Select a.BillingState, a.OwnerId from Account a where a.Id =:ID1];

       if((opp.StageName=='Contract')&&(opp.Number_of_Recruiters__c=='5-9') && (acct.BillingState == 'ME'||acct.BillingState == 'NH'

       ||acct.BillingState == 'VT'||acct.BillingState == 'NY'||acct.BillingState == 'PA'||acct.BillingState == 'DC'

       ||acct.BillingState == 'MD'||acct.BillingState == 'DE'||acct.BillingState == 'NJ'||acct.BillingState == 'CT'

       ||acct.BillingState == 'RI'||acct.BillingState == 'MA'))

       {

Line 30:        acct.ownerID =[select ID from User where name = 'Holly Esposito'].id;

         database.updata(acct);

         system.debug(opp.StageName);

         system.debug(acct.BillingState);

       }

       }

}

}

 

 

Compile Error: Initial term of field expression must be a concrete SObject: LIST<Account> at line 30

 

David81David81

Ok, here's my suggestion. Of course this is only a suggestion, but it worked well for me.

 

I'd go the custom setting route and store your territory/region data there so that if it needs altered (due to region shifts, additional regions, etc) it'll be easy to change. We set ours up with one entry per state and some identifier of the territory it belongs to. So if we add another territory, we just change the territory numbers on the state entries.You could also just use the user ID of the individual who owns that territory if you'd prefer to go that route.

 

Once you've got the custom settings set up keyed on the State as the name of each entry, it makes this much easier. Let's assume you set it up with the state name as the name of the records in the list and you've added another field that is the user ID. Then it'd go something like this.

 

 

trigger AccountAssignment on Opportunity (after insert,after update){

	//this assumes that your custom setting is "Territory_Assignment_Key__c". It could be anything you choose to name it.
	
	//get the assignment key data from memory. map key is the name field on the custom setting (state code assumed here)
	
	Map<String,Territory_Assignment_Key__c> keyMap = Territory_Assignment_Key__c.getAll(); 
	
	Set<Id> acctIds = new Set<Id>();
	
	for(Opportunity opp : trigger.new){
	
		if(opp.StageName=='Contract' && opp.Number_of_Recruiters__c=='5-9') {
			if(trigger.isInsert(){
				acctIds.add(opp.AccountId);
			}
			//on updates, only need to look at opps where the stage has changed
			else if(opp.StageName != trigger.oldMap.get(opp.Id).StageName){
				acctIds.add(opp.AccountId);
			}
		}
	
	}
	
	//only continue if we need to update some accts
	if(!acctIds.isEmpty()){
	
		List<Account> toUpdate = new List<Account>();
		
		for(Account a : [SELECT Id,OwnerId,BillingState FROM Account WHERE Id IN :acctIds]){
			//no need to change the owner if it's already the right one
			if(keyMap.containsKey(a.BillingState) && a.OwnerId != keyMap.get(a.BillingState)){
				a.OwnerId = keyMap.get(a.BillingState);
				toUpdate.add(a);
			}
		}
		
		if(!toUpdate.isEmpty()){
			Database.SaveResult[] updateResults = Database.update(toUpdate);
		}
	}

}

 

Hopefully that makes sense. Let me know if it doesn't.

 

TinkuTinku

Hi.

 

Pitched this idea to my manager. And he agreed to go this way.

Thanks a lot for your suggestions.

 

It is working perfectly fine now.