+ Start a Discussion
SurekaSureka 

Not able to specify access level while inserting Account Team member

Hi All,

 

I have a requirement to insert Account Team member when there is an update on account. While inserting the Account Team member I am not able to specify access level for Account. I am getting the below error -

Field is not writeable: AccountTeamMember.AccountAccessLevel.

 

Below is my code:

 

 

trigger AccountTeam on Account (after update) { for(Account a:trigger.new) { AccountTeamMember Teammemberad=new AccountTeamMember(); Teammemberad.AccountId=a.id; Teammemberad.UserId='00580000001nhJT'; Teammemberad.TeamMemberRole = 'Account Manager'; Teammemberad.AccountAccessLevel= 'Read'; insert Teammemberad; } }

 

Also I need to specify access levels for Contact, Opportunity and Cases for which I am not able to find out.

Any suggestion on this will be of great help!!!

 

Thanks in advance!!

 

 

 

 

 

Best Answer chosen by Admin (Salesforce Developers) 
JimRaeJimRae

You actually need to specify the access level from the share object. So, for example, with the account team, you need to add the user to the account team, and then add a record to the AccountShare table with the appropriate access.

Also, to make your trigger more effecient and bulk safe, I would recommend you create a list of items to add, then add them in one DML statement.

 

Something like this:

 

 

trigger AccountTeam on Account (after update) { AccountTeamMember[] newmembers = new AccountTeamMember[]{}; //list of new team members to add AccountShare[] newShare = new AccountShare[]{}; //list of new shares to add for(Account a:trigger.new){ AccountTeamMember Teammemberad=new AccountTeamMember(); Teammemberad.AccountId=a.id; Teammemberad.UserId='00580000001nhJT'; Teammemberad.TeamMemberRole = 'Account Manager'; newmembers.add(Teammemberad); } Database.SaveResult[] lsr = Database.insert(newmembers,false);//insert any valid members then add their share entry if they were successfully added Integer newcnt=0; for(Database.SaveResult sr:lsr){ if(!sr.isSuccess()){ Database.Error emsg =sr.getErrors()[0]; system.debug('\n\nERROR ADDING TEAM MEMBER:'+emsg); }else{ newShare.add(new AccountShare(UserOrGroupId=newmembers[newcnt].UserId, AccountId=newmembers[newcnt].Accountid, AccountAccessLevel='Read',OpportunityAccessLevel='Read')); } newcnt++; } Database.SaveResult[] lsr0 =Database.insert(newShare,false); //insert the new shares Integer newcnt0=0; for(Database.SaveResult sr0:lsr0){ if(!sr0.isSuccess()){ Database.Error emsg0=sr0.getErrors()[0]; system.debug('\n\nERROR ADDING SHARING:'+newShare[newcnt0]+'::'+emsg0); } newcnt0++; } }

 


 

 

All Answers

JimRaeJimRae

You actually need to specify the access level from the share object. So, for example, with the account team, you need to add the user to the account team, and then add a record to the AccountShare table with the appropriate access.

Also, to make your trigger more effecient and bulk safe, I would recommend you create a list of items to add, then add them in one DML statement.

 

Something like this:

 

 

trigger AccountTeam on Account (after update) { AccountTeamMember[] newmembers = new AccountTeamMember[]{}; //list of new team members to add AccountShare[] newShare = new AccountShare[]{}; //list of new shares to add for(Account a:trigger.new){ AccountTeamMember Teammemberad=new AccountTeamMember(); Teammemberad.AccountId=a.id; Teammemberad.UserId='00580000001nhJT'; Teammemberad.TeamMemberRole = 'Account Manager'; newmembers.add(Teammemberad); } Database.SaveResult[] lsr = Database.insert(newmembers,false);//insert any valid members then add their share entry if they were successfully added Integer newcnt=0; for(Database.SaveResult sr:lsr){ if(!sr.isSuccess()){ Database.Error emsg =sr.getErrors()[0]; system.debug('\n\nERROR ADDING TEAM MEMBER:'+emsg); }else{ newShare.add(new AccountShare(UserOrGroupId=newmembers[newcnt].UserId, AccountId=newmembers[newcnt].Accountid, AccountAccessLevel='Read',OpportunityAccessLevel='Read')); } newcnt++; } Database.SaveResult[] lsr0 =Database.insert(newShare,false); //insert the new shares Integer newcnt0=0; for(Database.SaveResult sr0:lsr0){ if(!sr0.isSuccess()){ Database.Error emsg0=sr0.getErrors()[0]; system.debug('\n\nERROR ADDING SHARING:'+newShare[newcnt0]+'::'+emsg0); } newcnt0++; } }

 


 

 

This was selected as the best answer
SurekaSureka

Hey Jim,

 

The solution worked great!!!!

 

Thanks a ton!!

 

JAW99JAW99

Jim, nice code. I am having trouble changing this to add the current user as Account Team member. Can you help?

 

Also, what about the idea proposed in this message: http://community.salesforce.com/sforce/board/message?board.id=apex&view=by_date_ascending&message.id=24696#M24696

 

Upon insert, add creator to acct team but transfer ownership to another (fixed) use?

 

thanks!

JimRaeJimRae

Here is a modified version that adds the current user modifying the Account to the account team.

 

 

trigger AccountTeam on Account (after update) { AccountTeamMember[] newmembers = new AccountTeamMember[]{}; //list of new team members to add AccountShare[] newShare = new AccountShare[]{}; //list of new shares to add ID uid = UserInfo.getUserId(); //get the user id of the user running the trigger, anyone that changes the Account will added to the account team for(Account a:trigger.new){ AccountTeamMember Teammemberad=new AccountTeamMember(); Teammemberad.AccountId=a.id; Teammemberad.UserId=uid; Teammemberad.TeamMemberRole = 'Account Modifier'; newmembers.add(Teammemberad); } Database.SaveResult[] lsr = Database.insert(newmembers,false);//insert any valid members then add their share entry if they were successfully added Integer newcnt=0; for(Database.SaveResult sr:lsr){ if(!sr.isSuccess()){ Database.Error emsg =sr.getErrors()[0]; system.debug('\n\nERROR ADDING TEAM MEMBER:'+emsg); }else{ newShare.add(new AccountShare(UserOrGroupId=newmembers[newcnt].UserId, AccountId=newmembers[newcnt].Accountid, AccountAccessLevel='Read',OpportunityAccessLevel='Read')); } newcnt++; } Database.SaveResult[] lsr0 =Database.insert(newShare,false); //insert the new shares Integer newcnt0=0; for(Database.SaveResult sr0:lsr0){ if(!sr0.isSuccess()){ Database.Error emsg0=sr0.getErrors()[0]; system.debug('\n\nERROR ADDING SHARING:'+newShare[newcnt0]+'::'+emsg0); } newcnt0++; } }

 

 For your on insert, this is a bit more tricky, because the Account ID doesn't exist until after the commit happens.  You have to be cautious you don't get into a looping situation. I will have to think about that one, unless someone else jumps in first.

 

 

 

 

 

JAW99JAW99
Thanks Jim, interesting stuff. am also thinking about how to control what team role the person is assigned based on who they are. sounds potentially complicated to this inexperienced guy.
JAW99JAW99

Tried to assign user Department to the Acct Team Role but get a

 

 Error: Compile Error: Illegal assignment from Schema.SObjectField to String at line 9 column 11

 

 Teammemberad.TeamMemberRole = User.Department;

JimRaeJimRae

User.department is a field name. You would need to query the user object for this data, then get a string out, and then you could use it:

Here is a modified version of the code:

 

 

trigger AccountTeam on Account (after update) { AccountTeamMember[] newmembers = new AccountTeamMember[]{}; //list of new team members to add AccountShare[] newShare = new AccountShare[]{}; //list of new shares to add User currentuser = [select id,name,department from user where id=:UserInfo.getUserId() LIMIT 1]; //get the user running the trigger, anyone that changes the Account will added to the account team ID uid=currentuser.id; String dept=currentuser.department; for(Account a:trigger.new){ AccountTeamMember Teammemberad=new AccountTeamMember(); Teammemberad.AccountId=a.id; Teammemberad.UserId=uid; Teammemberad.TeamMemberRole = dept; newmembers.add(Teammemberad); } Database.SaveResult[] lsr = Database.insert(newmembers,false);//insert any valid members then add their share entry if they were successfully added Integer newcnt=0; for(Database.SaveResult sr:lsr){ if(!sr.isSuccess()){ Database.Error emsg =sr.getErrors()[0]; system.debug('\n\nERROR ADDING TEAM MEMBER:'+emsg); }else{ newShare.add(new AccountShare(UserOrGroupId=newmembers[newcnt].UserId, AccountId=newmembers[newcnt].Accountid, AccountAccessLevel='Read',OpportunityAccessLevel='Read')); } newcnt++; } Database.SaveResult[] lsr0 =Database.insert(newShare,false); //insert the new shares Integer newcnt0=0; for(Database.SaveResult sr0:lsr0){ if(!sr0.isSuccess()){ Database.Error emsg0=sr0.getErrors()[0]; system.debug('\n\nERROR ADDING SHARING:'+newShare[newcnt0]+'::'+emsg0); } newcnt0++; } }

 

 

JAW99JAW99

Jim, thanks.

I just tested this, worked fine. Changed it to an "after insert" and also worked! 

JAW99JAW99

I have combined the above with this trigger below:

 

 

trigger testChangeOwnerTrigger on Account (before insert) { for(Account newAccount : Trigger.New){ newAccount.OwnerId ='00530000000iMRl'; } }

 

 

in my sandbox and upon create I get both to work - the account is transferred to the designated owner and the creator is added to account team with role based on department.

I am not skilled enough to write test methods but i bet this could be deployed through change sets.Are there any issues that jump out about using these?

Have not fully decided to implement but like the possibilities.

JAW99JAW99

Thanks gain Jim.

OK, now I am trying to rework that trigger to add a certtain user to a Case team upon creation of a case of a certain record type but am running into some issues...

JAW99JAW99

trigger CaseTeamCreator on Case (after insert) {
     CaseTeamMember[] newmembers = new CaseTeamMember[]{};  //list of new team members to add
     CaseShare[] newShare = new CaseShare[]{};  //list of new shares to add
     User currentuser =  [select id,name,department from user where id=:UserInfo.getMemberId() LIMIT 1];  //get the user running the trigger, anyone that changes the Case will added to the Case team
    ID uid=currentuser.id;
    String dept=currentuser.Department;
     for(Case a:trigger.new){
          CaseTeamMember Teammemberad=new CaseTeamMember();
          Teammemberad.ParentId=a.id;
          Teammemberad.MemberId=uid;
          Teammemberad.TeamRoleId = dept;
          newmembers.add(Teammemberad);
     }
     Database.SaveResult[] lsr = Database.insert(newmembers,false);//insert any valid members then add their share entry if they were successfully added
     Integer newcnt=0;
     for(Database.SaveResult sr:lsr){
    if(!sr.isSuccess()){
        Database.Error emsg =sr.getErrors()[0];
        system.debug('\n\nERROR ADDING TEAM MEMBER:'+emsg);
    }else{
        newShare.add(new CaseShare(UserOrGroupId=newmembers[newcnt].MemberId, CaseId=newmembers[newcnt].Caseid, CaseAccessLevel='Full'));
    }
    newcnt++;           
     }
     Database.SaveResult[] lsr0 =Database.insert(newShare,false); //insert the new shares
     Integer newcnt0=0;
     for(Database.SaveResult sr0:lsr0){
    if(!sr0.isSuccess()){
         Database.Error emsg0=sr0.getErrors()[0];
         system.debug('\n\nERROR ADDING SHARING:'+newShare[newcnt0]+'::'+emsg0);
    }
    newcnt0++;
     }
}

JimRaeJimRae

Looks like your only error is that you are using a method "getMemberID()" on the UserInfo, and that doesn't appear to exist.

You should use getUserID(), like we did on the account trigger.

It appears, what your code would do is after a case is created, it would add the creator to the case team (with the change I suggested).  It you want something to do both creation and update, you would need to change your trigger to (after insert, after update)  Otherwise, it would only fire when the case is inserted.



 

 

JAW99JAW99

Right, what I'd like would be one that only on certain cases, adds a speciic user id, not current user, but am not able to put that in, running into syntax errors. Setting specified text... a role, etc.

JimRaeJimRae

So, to add a specific user, that is not the running user, you would need to add a second query to the code to get that user object record, you will need to update the query to find the user correctly. Then you could add it to the teammember list and it would get added with the rest.

 

 

trigger CaseTeamCreator on Case (after insert) {
     CaseTeamMember[] newmembers = new CaseTeamMember[]{};  //list of new team members to add
     CaseShare[] newShare = new CaseShare[]{};  //list of new shares to add
     User currentuser =  [select id,name,department from user where id=:UserInfo.getUserId() LIMIT 1];  //get the user running the trigger, anyone that changes the Case will added to the Case team
    ID uid=currentuser.id;
    String dept=currentuser.Department;
    User standinguser = [select id,name,department from user where name = 'Joe Smith' LIMIT 1];//new common user that always gets added
    ID stid =standinguser.id;
    String stddept = standinguser.department;
     for(Case a:trigger.new){
          CaseTeamMember Teammemberad=new CaseTeamMember();
          Teammemberad.ParentId=a.id;
          Teammemberad.MemberId=uid;
          Teammemberad.TeamRoleId = dept;
          newmembers.add(Teammemberad);
          CaseTeamMember stTeammemberad=new CaseTeamMember();
          stTeammemberad.ParentId=a.id;
          stTeammemberad.MemberId=stid;
          stTeammemberad.TeamRoleId = stddept;
          newmembers.add(stTeammemberad);

     }
     Database.SaveResult[] lsr = Database.insert(newmembers,false);//insert any valid members then add their share entry if they were successfully added
     Integer newcnt=0;
     for(Database.SaveResult sr:lsr){
    if(!sr.isSuccess()){
        Database.Error emsg =sr.getErrors()[0];
        system.debug('\n\nERROR ADDING TEAM MEMBER:'+emsg);
    }else{
        newShare.add(new CaseShare(UserOrGroupId=newmembers[newcnt].MemberId, CaseId=newmembers[newcnt].Caseid, CaseAccessLevel='Full'));
    }
    newcnt++;           
     }
     Database.SaveResult[] lsr0 =Database.insert(newShare,false); //insert the new shares
     Integer newcnt0=0;
     for(Database.SaveResult sr0:lsr0){
    if(!sr0.isSuccess()){
         Database.Error emsg0=sr0.getErrors()[0];
         system.debug('\n\nERROR ADDING SHARING:'+newShare[newcnt0]+'::'+emsg0);
    }
    newcnt0++;
     }
}

 

 

JAW99JAW99

I am getting an error on this line:

 

Teammemberad.TeamRoleId = dept;

 

Apex trigger CaseTeamCreator caused an unexpected exception, contact your administrator: CaseTeamCreator: execution of AfterInsert caused by: System.StringException: Invalid id: ELX Support: Trigger.CaseTeamCreator: line 14, column 11

 

It looks like what I need is the SFID of the Case Team Role, right?

 

I think I can cut out the running user that gets added, will work for me and simplify the trigger...

JimRaeJimRae

Yes, it appears you need the id.  I don't have this type of Case trigger implemented, as we don't use cases that way, so my code was all theoretical.  If you are somehow mapping the user's department to a case team role, you will probably have to create a map of all of the case team roles, with the name as the key field and the ID as a value in the map, then search for it by looping through the map.  IF the department doesn't exist, you will need to either have error handling or a default role you want to use.

JAW99JAW99

Hah, yes, it works when I put the role ID into users' Dept field, but that's not a real solution...

 

So I got it to do only the standing user:

 

trigger CaseTeamCreator on Case (after insert) {
     CaseTeamMember[] newmembers = new CaseTeamMember[]{};  //list of new team members to add
     CaseShare[] newShare = new CaseShare[]{};  //list of new shares to add
    
    User standinguser = [select id,name,department from user where name = 'Joe Smith' LIMIT 1];//new common user that always gets added
    ID stid =standinguser.id;
    String stddept = standinguser.department;
     for(Case a:trigger.new){
      
          CaseTeamMember stTeammemberad=new CaseTeamMember();
          stTeammemberad.ParentId=a.id;
          stTeammemberad.MemberId=stid;
          stTeammemberad.TeamRoleId = stddept;
          newmembers.add(stTeammemberad);

 

But need to change dept to the Role id, fixed. and add the "where case Record type = ..."

JAW99JAW99

Just want Role Id fixed, since it's one Record Type of cases and want to add one user, always...

JAW99JAW99

Jim, thanks for your help. I got to set it to a defined role for standing user. Can yuo asist me with building a test method so I can deploy?

trigger CaseTeamCreator on Case (after insert) {

     CaseTeamMember[] newmembers = new CaseTeamMember[]{};  //list of new team members to add
     CaseShare[] newShare = new CaseShare[]{};  //list of new shares to add
    
    User standinguser = [select id,name,CaseRole__c from user where name = 'Christopher Curtin' LIMIT 1];//new common user that always gets added
    ID stid =standinguser.id;
    String stddept = standinguser.CaseRole__c;
     for(Case a:trigger.new){
      
      IF(a.RecordTypeId=='012400000009bNP')
      {
          CaseTeamMember stTeammemberad=new CaseTeamMember();
          stTeammemberad.ParentId=a.id;
          stTeammemberad.MemberId=stid;
          stTeammemberad.TeamRoleId = stddept;
          newmembers.add(stTeammemberad);
}
     }
     Database.SaveResult[] lsr = Database.insert(newmembers,false);//insert any valid members then add their share entry if they were successfully added
     Integer newcnt=0;
     for(Database.SaveResult sr:lsr){
    if(!sr.isSuccess()){
        Database.Error emsg =sr.getErrors()[0];
        system.debug('\n\nERROR ADDING TEAM MEMBER:'+emsg);
    }else{
        newShare.add(new CaseShare(UserOrGroupId=newmembers[newcnt].MemberId, CaseId=newmembers[newcnt].Parentid, CaseAccessLevel='Full'));
    }
    newcnt++;           
     }
     Database.SaveResult[] lsr0 =Database.insert(newShare,false); //insert the new shares
     Integer newcnt0=0;
     for(Database.SaveResult sr0:lsr0){
    if(!sr0.isSuccess()){
         Database.Error emsg0=sr0.getErrors()[0];
         system.debug('\n\nERROR ADDING SHARING:'+newShare[newcnt0]+'::'+emsg0);
    }
    newcnt0++;
     }
}
JimRaeJimRae

This should get you started.

 

 

/** This Test method is designed to support the testing of the CaseTeam Member Common user team additon Trigger
  * Created on 9/8/2010
 */
@isTest
private class testActivityTrendSnapshot {

	static testMethod void myUnitTest() {
		string tcaseid;
		User standinguser = [select id,name,CaseRole__c from user where name = 'Christopher Curtin' LIMIT 1];
		
		Test.StartTest();
		
		Case testcase = new Case(name=testcase, status ='Open',Recordtypeid='012400000009bNP');  //add other required fields as necessary
		
		try{
			insert testcase;
			tcaseid=testcase.id;
		}catch(DMLException d){
			system.assert(false, '\n\nERROR OCCURRED INSERTING TEST CASE: '+d.getDMLMessage(0));
		}
		
		Test.StopTest();
		
		//Start validation
		Case[] checkcase = [select id,name from case where id=:tcaseid];
		system.assert(checkcase.size()>0,'\n\nCase doesn't Exist');
		
		CaseTeamMember[] findMember = [select id,memberid,TeamRoleId from CaseTeamMember where ParentID=:tcaseid and Memberid=:standinguser.id];
		system.assert(findMember.size()>0,'\n\nCaseMember was not added correctly');

	}
}

	

 

 

jhittlemanjhittleman

Hey Jim, great stuff here, going back to the original CaseTeamCreator trigger that adds the currentuser to the case team when a case is created, can you help with out with an apex class so I can deploy the trigger?

 

 

trigger CaseTeamCreator on Case (after insert) {
     CaseTeamMember[] newmembers = new CaseTeamMember[]{};  //list of new team members to add
     CaseShare[] newShare = new CaseShare[]{};  //list of new shares to add
     User currentuser =  [select id,name,department from user where id=:UserInfo.getMemberId() LIMIT 1];  //get the user running the trigger, anyone that changes the Case will added to the Case team
    ID uid=currentuser.id;
    String dept=currentuser.Department;
     for(Case a:trigger.new){
          CaseTeamMember Teammemberad=new CaseTeamMember();
          Teammemberad.ParentId=a.id;
          Teammemberad.MemberId=uid;
          Teammemberad.TeamRoleId = dept;
          newmembers.add(Teammemberad);
     }
     Database.SaveResult[] lsr = Database.insert(newmembers,false);//insert any valid members then add their share entry if they were successfully added
     Integer newcnt=0;
     for(Database.SaveResult sr:lsr){
    if(!sr.isSuccess()){
        Database.Error emsg =sr.getErrors()[0];
        system.debug('\n\nERROR ADDING TEAM MEMBER:'+emsg);
    }else{
        newShare.add(new CaseShare(UserOrGroupId=newmembers[newcnt].MemberId, CaseId=newmembers[newcnt].Caseid, CaseAccessLevel='Read/Write'));
    }
    newcnt++;           
     }
     Database.SaveResult[] lsr0 =Database.insert(newShare,false); //insert the new shares
     Integer newcnt0=0;
     for(Database.SaveResult sr0:lsr0){
    if(!sr0.isSuccess()){
         Database.Error emsg0=sr0.getErrors()[0];
         system.debug('\n\nERROR ADDING SHARING:'+newShare[newcnt0]+'::'+emsg0);
    }
    newcnt0++;
     }
}

 

 

JimRaeJimRae

Something like this should work:

 

 

/** This Test method is designed to support the testing of the CaseTeam Member Common user team addition Trigger
  * Created on 12/2/2010
 */
@isTest
private class testCaseTeamMember {

	static testMethod void myUnitTest() {
		string tcaseid;
		ID createuserID Userinfo.getUserid();
		
		Test.StartTest();
		
		Case testcase = new Case(name='testcase', status ='Open',Recordtypeid='012400000009bNP');  //add other required fields as necessary
		
		try{
			insert testcase;
			tcaseid=testcase.id;
		}catch(DMLException d){
			system.assert(false, '\n\nERROR OCCURRED INSERTING TEST CASE: '+d.getDMLMessage(0));
		}
		
		Test.StopTest();
		
		//Start validation
		Case[] checkcase = [select id,name from case where id=:tcaseid];
		system.assert(checkcase.size()>0,'\n\nCase doesn't Exist');
		
		CaseTeamMember[] findMember = [select id,memberid,TeamRoleId from CaseTeamMember where ParentID=:tcaseid and Memberid=:createuserid];
		system.assert(findMember.size()>0,'\n\nCaseMember was not added correctly');

	}
}

 

 

jhittlemanjhittleman

Thanks Jim. If I wanted to limit the trigger to only occur on certain Case Record Types, how would I represent that in the trigger?

JimRaeJimRae

YOu would need to modify the loop on the Trigger.new to use an "If" condition.

for(Case a:trigger.new){
     if(a.recordtypeid=='xxxxxxxxxxxxxxx' ||a.recordtypeid=='yyyyyyyyyyyy'){
         CaseTeamMember Teammemberad=new CaseTeamMember();
          Teammemberad.ParentId=a.id;
          Teammemberad.MemberId=uid;
          Teammemberad.TeamRoleId = dept;
          newmembers.add(Teammemberad);
     }

 

 

jhittlemanjhittleman

OK thanks. I really appreciate your help on this.

jaw999jaw999

Reviving an old post that helped me out a lot in the past -

thoughts on making the new teamMember's access to Opportunity still private? I have a larger code piece that inserts acct teams and chatter subscriptions upon creation of a new custom object matching account coverage from an internal system, but am not quite able to get Read Only access to stick. Inserting a new opportunity share object wouldn't work b/c there's no opportunity to reference. Thoughts? thanks