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
jbroquistjbroquist 

Issues with managing the Account Team through a Trigger

On our opportunity object, we have a custom user relationship field called "Processor". The processor for each opportunity is dynamically set based on the opportunity owner, when the opportunity record is initially created. I have created a custom trigger to then add the chosen processor to the parent Account Team with full editing privileges, and remove any other processors from the Account Team that may already exists.

 

Here is the trigger code:

 

/**
* Title: AddProcessorToAccountTeam
* Author: Jonathan Broquist
* Date: April 28, 2010
*
* Description:
* Everytime the processor relationship field is changed on an Opportunity,
* add the new user to the Account Team of the parent Account.
*/
trigger AddProcessorToAccountTeam on Opportunity (after insert, after update)
{
//list to hold new account team members
List<AccountTeamMember> acctMembers = new List<AccountTeamMember>();

//list to hold new account sharing rules
List<AccountShare> acctSharingRules = new List<AccountShare>();

//misc
Set<String> rmMemberAccts = new Set<String>();
Map<ID, ID> acctToProcessorMap = new Map<ID, ID>();

//iterate through records to find update processor values
for(Opportunity o : Trigger.new)
{
//new opportunity
if(Trigger.isInsert && o.Processor__c != null)
{
AccountTeamMember processor = new AccountTeamMember();
processor.AccountId = o.AccountId;
processor.TeamMemberRole = 'Processor';
processor.UserId = o.Processor__c;
acctMembers.add(processor);

AccountShare processorSharingRule = new AccountShare();
processorSharingRule.AccountId = o.AccountId;
processorSharingRule.OpportunityAccessLevel = 'Edit';
processorSharingRule.CaseAccessLevel = 'Read';
processorSharingRule.AccountAccessLevel = 'Edit';
processorSharingRule.UserOrGroupId = o.Processor__c;
acctSharingRules.add(processorSharingRule);
}
//updated opportunity
else if(Trigger.isUpdate)
{
//old opportunity record
Opportunity oldOpp = Trigger.oldMap.get(o.Id);

//check to see if the processor value has changed and verifies the
//new value is not null
if(oldOpp.Processor__c != o.Processor__c && o.Processor__c != null)
{
//add old processor to remove list if one exists
if(oldOpp.Processor__c != null)
{
rmMemberAccts.add(oldOpp.AccountId);
acctToProcessorMap.put(oldOpp.AccountId, oldOpp.Processor__c);
}

//add new processor to account team and update sharing rules
AccountTeamMember processor = new AccountTeamMember();
processor.AccountId = o.AccountId;
processor.TeamMemberRole = 'Processor';
processor.UserId = o.Processor__c;
acctMembers.add(processor);

AccountShare processorSharingRule = new AccountShare();
processorSharingRule.AccountId = o.AccountId;
processorSharingRule.OpportunityAccessLevel = 'Edit';
processorSharingRule.CaseAccessLevel = 'Read';
processorSharingRule.AccountAccessLevel = 'Edit';
processorSharingRule.UserOrGroupId = o.Processor__c;
acctSharingRules.add(processorSharingRule);
}
else if(oldOpp.Processor__c != o.Processor__c && o.Processor__c == null)
{
rmMemberAccts.add(o.AccountId);
acctToProcessorMap.put(oldOpp.AccountId, oldOpp.Processor__c);
}
}

//DML OPERATIONS
//remove team members from account team if any exist
if(rmMemberAccts.size() > 0)
{
List<AccountTeamMember> removeTeam = new List<AccountTeamMember>();
for(AccountTeamMember atm : [SELECT Id, UserId, AccountId FROM AccountTeamMember WHERE TeamMemberRole='Processor' AND AccountId IN :rmMemberAccts])
{
if(atm.UserId == acctToProcessorMap.get(atm.AccountId))
removeTeam.add(atm);
}

delete removeTeam;
}

system.debug('-->ACCOUNT MEMBERS: ' + acctMembers);
//insert the new account team members if any exist
if(acctMembers.size() > 0)
insert acctMembers; //LINE 100

//insert account sharing rules if any exist
if(acctSharingRules.size() > 0)
insert acctSharingRules;
}

}

 

Here is a snippet of the unit test that appears to causing the issues. Basically just batch creating opportunities...

 

 

//bulk insert opportunities
        Integer numOfOpps = 30;
        List<Opportunity> newOpps = new List<Opportunity>();
        for(Integer i=0; i<numOfOpps; i++)
        {
        	Opportunity o = new Opportunity();
	        o.Name = 'Test Opp';
	        o.AccountId = a.Id;
	        o.StageName = 'First Appointment';
	        o.Type = 'Outside Sales';
	        o.CloseDate = system.today() + 60;
	        newOpps.add(o);
        }
        
        Database.Saveresult[] oppResults = database.insert(newOpps);

 

Here is the relevant debug stack log:

 

19:47:21.392|USER_DEBUG|[97,4]|DEBUG|-->ACCOUNT MEMBERS: (AccountTeamMember:{AccountId=001R000000U0Iz0IAF, Id=01MR0000001JohsMAC, UserId=00540000000oDrMAAU, TeamMemberRole=Processor}, AccountTeamMember:{AccountId=001R000000U0Iz0IAF, UserId=00540000000oDrMAAU, TeamMemberRole=Processor})
19:47:21.392|METHOD_EXIT|[97,4]|debug(ANY)
19:47:21.392|METHOD_ENTRY|[99,7]|LIST:SOBJECT:AccountTeamMember.size()
19:47:21.392|METHOD_EXIT|[99,7]|size()
19:47:21.392|DML_BEGIN|[100,5]|Op:Insert|Type:AccountTeamMember|Rows:2
19:47:21.417|DML_END|[100,5]|
19:47:21.417|VF_PAGE_MESSAGE|cannot specify Id in an insert call
19:47:21.417|EXCEPTION_THROWN|[100,5]|System.DmlException: Insert failed. First exception on row 0 with id 01MR0000001JohsMAC; first error: INVALID_FIELD_FOR_INSERT_UPDATE, cannot specify Id in an insert call: [Id]
19:47:21.423|FATAL_ERROR|System.DmlException: Insert failed. First exception on row 0 with id 01MR0000001JohsMAC; first error: INVALID_FIELD_FOR_INSERT_UPDATE, cannot specify Id in an insert call: [Id]

Trigger.AddProcessorToAccountTeam: line 100, column 5

 

The bolded area is a debug output showing the values of the list of Account Team Memebers attempting to be inserted.

 

I cannot for the life of me figure out why an ID field is being passed to one of the AccountTeamMemeber records, and not the others.

 

Any thoughts or inisght would be greatly appreciated... I've been banging my head against this issue for quite some time.

 

 

Sincerely,

Jonathan

 

Best Answer chosen by Admin (Salesforce Developers) 
WesNolte__cWesNolte__c

Hey

 

Presumably you're running through this loop more than once:

 

for(Opportunity o : Trigger.new)

The second time around 'acctMembers' already has objects with Ids in the list. You may want to clear the list as a last step (or even reinstantiate it).

 

Wes

All Answers

WesNolte__cWesNolte__c

Hey

 

Presumably you're running through this loop more than once:

 

for(Opportunity o : Trigger.new)

The second time around 'acctMembers' already has objects with Ids in the list. You may want to clear the list as a last step (or even reinstantiate it).

 

Wes

This was selected as the best answer
jbroquistjbroquist

Wow I feel like a noob ... I didn't realize I had my DML operations in the FOR loop. Thanks for pointing that out!!!