+ Start a Discussion
sam_Adminsam_Admin 

Trigger to forward related contacts with account in s2s

Right now I am using the below trigger to forward an Opportunity via Salesforce2Salesforce. Is it possible to transfer related contacts along with account?
Trigger Description: Whenever Department is set to "US" then the Opp automatically gets forwarded to Connection


Trigger AutoforwardOpp on Opportunity(after insert, before update)
{
    String UserName = UserInfo.getName();
    String orgName = UserInfo.getOrganizationName();
    List<PartnerNetworkConnection> connectionList = new List<PartnerNetworkConnection>();
    List<PartnerNetworkConnection> connMap = new List<PartnerNetworkConnection>
    ([select Id, ConnectionStatus, ConnectionName from PartnerNetworkConnection where ConnectionStatus = 'Accepted']);
    List<PartnerNetworkRecordConnection> prncList = new List<PartnerNetworkRecordConnection>();

    for(Integer i =0; i< Trigger.size; i++)
    {
        Opportunity opp = Trigger.new[i];
        String oId = opp.Id;
        String accId = opp.AccountId;
        for(PartnerNetworkConnection network : connMap)
        {

            String cid = network.Id;
            String status = network.ConnectionStatus;
            String connName = network.ConnectionName;

            if(opp.Department__c == 'US')
            {
                PartnerNetworkRecordConnection newAccRecord = new PartnerNetworkRecordConnection();
                newAccRecord.ConnectionId = cid;
                newAccRecord.LocalRecordId = accId;
                newAccRecord.SendClosedTasks = true;
                newAccRecord.SendOpenTasks = true;
                newAccRecord.SendEmails = true;
                System.debug('Inserting New Record'+newAccrecord);
                insert newAccrecord;

                PartnerNetworkRecordConnection newOpprecord = new PartnerNetworkRecordConnection();
                newOpprecord.ConnectionId = cid;
                newOpprecord.LocalRecordId = oId;
                newOpprecord.SendClosedTasks = true;
                newOpprecord.SendOpenTasks = true;
                newOpprecord.SendEmails = true;
                System.debug('Inserting New Record'+newOpprecord);
                insert newOpprecord;
            }
        }
    }
}
Best Answer chosen by sam_Admin
jigarshahjigarshah
Sam,

The code is rectified and verified it at my end and it works as expected. This should work fine for you without any errors. Also, since the records are shared using a Salesforce to Salesforce connection, they should be done when the DML operations successfully commit their values to the database or else it might result in inconistency. Hence I have changed the trigger to fire on After Insert and After Update events.
 
Trigger AutoforwardOpp on Opportunity(after insert, after update)
{
	List <PartnerNetworkRecordConnection> prncList;
	List <PartnerNetworkConnection> connectionList;
	Map <ID, PartnerNetworkConnection> connMap;
	Map <ID, ID> oppIdvsAccountIdMap;
	Map<ID, Account> accountWithContactMap;
    
    ID cid;
	String status;
	String connName;

	if(Trigger.isAfter && (Trigger.isInsert || Trigger.isUpdate)){
			
		connectionList = new List<PartnerNetworkConnection>();
		prncList = new List<PartnerNetworkRecordConnection>();
		
		//This would ideally return multiple active Connections if they exist hence its best you use a 
		//criteria to ensure only the appropriate connection record is returned. 
		connMap = new Map<ID, PartnerNetworkConnection>(
			[Select ID, ConnectionStatus, ConnectionName 
			 From PartnerNetworkConnection 
			 Where ConnectionStatus = 'Accepted']);
		
		//get connection details		
		for(ID connId :connMap.keySet()){
			cid = connMap.get(connId).ID;
            status = connMap.get(connId).ConnectionStatus;
            connName = connMap.get(connId).ConnectionName;
		}
		
		//Populate a map of Opp Ids and associated Account Ids
		oppIdvsAccountIdMap = new Map<ID, ID>();
		for(Opportunity oppRecord :Trigger.new){
		
			if(oppRecord.Department__c == 'US'){
					oppIdvsAccountIdMap.put(oppRecord.ID, oppRecord.Account.ID);
			}
		}
		
		//Get associated Accounts and Contacts for every US opportunity if they exist
		if(oppIdvsAccountIdMap.keySet().size() > 0){
		
			accountWithContactMap = new Map<ID, Account>(
				[Select ID, Name,
					(Select ID, Name From Account.Contacts)
				 From Account
				 Where ID IN :oppIdvsAccountIdMap.values()]);

			//Create PartnerNetworkRecordConnections for sharing the records
			for(ID oppId : oppIdvsAccountIdMap.keySet()){
			
				ID accountId = oppIdvsAccountIdMap.get(oppId);
				
				//Share Opportunity
				prncList.add(new PartnerNetworkRecordConnection(
					ConnectionId = cid,
					LocalRecordId = oppId,
					SendClosedTasks = true,
					SendOpenTasks = true,
					SendEmails = true));
				
				//Share Account
				if(oppIdvsAccountIdMap.get(oppId) != null){
				
					prncList.add(new PartnerNetworkRecordConnection(
                        ConnectionId = cid,
                        LocalRecordId = accountId,
                        SendClosedTasks = true,
                        SendOpenTasks = true,
                        SendEmails = true));
				}
				
				//Share associated Contacts
				if(accountWithContactMap.get(accountId).Contacts != null){
				
					for(Contact contact :accountWithContactMap.get(accountId).Contacts){
					
						prncList.add(new PartnerNetworkRecordConnection(
							ConnectionId = cid,
							LocalRecordId = contact.ID,
							SendClosedTasks = true,
							SendOpenTasks = true,
							SendEmails = true));
					}
				}
			}//for
			
			//Insert record conneections
			if(!prncList.isEmpty()){
			
				try{
					insert prncList;
				}
				catch(System.Dmlexception dmlExceptionInstance){
					System.debug('Record Share Error:' + dmlExceptionInstance.getMessage());
				}
			}
		}//if
	}
}
Please do not forget to mark this thread as SOLVED and answer as the BEST ANSWER if it helps resolve your issue.

All Answers

jigarshahjigarshah
Yes this possible. You already have the Record Id of the Account Record available in the accId variable. So all you need to do is query the associated Contacts for the Account record and then create a PartnerNetworkRecordConnnection for each retrieved Contact as you are already doing it.

Refer the sample code below to do so.
List<PartnerNetworkRecordConnection> s2sContactRecShareList = new List<PartnerNetworkRecordConnection>();

for(Contact contactRecord :[Select Id, Name 
							From Contact 
							Where Contact.Account = :accId]){

	PartnerNetworkRecordConnection newContactRecConn = new PartnerNetworkRecordConnection();
	newContactRecConn.ConnectionId = cid;
	newContactRecConn.LocalRecordId = contactRecord.Id;
	newContactRecConn.SendClosedTasks = true;
	newContactRecConn.SendOpenTasks = true;
	newContactRecConn.SendEmails = true;
	System.debug('Creating New Contact Share Record' + newContactRecConn);
	s2sContactRecShareList.add(newContactRecConn);
}

if(!s2sContactRecShareList.isEmpty()){
	try{
		insert(s2sContactRecShareList)
	}
	catch(System.DmlException dmlException){
		System.debug('Exception: ' + dmlException.getMessage());
	}
}
Moreover, you have insert statements written within a for loop which makes your code prone to hitting DML Limits. You would want to hold all the PartnerNetworkRecordConnection records within a List and would want to insert that list rather than doign inserts on an individual list. You may want to look at how to bulkify your Apex code (https://developer.salesforce.com/page/Best_Practice%3A_Bulkify_Your_Code) to avoid hitting the limits.

Please do not forget to mark this thread as SOLVED and answer as the BEST ANSWER if it helps resolve your issue.
sam_Adminsam_Admin
Hey thank you for the solution, iam new to triggers is it possible to update my above code? that would be so helpful 
sam_Adminsam_Admin
I got the error "unexpected syntax: 'extraneous input ';' expecting RPAREN' at line 47 column 122"
sam_Adminsam_Admin
I fixed that but now iam getting error here String cid = network.Id;
Illegal assignment from Schema.SObjectField to String at line 13 column 16
jigarshahjigarshah
You will need change line # 13 in your code as follows. This erro occurs because the network.Id is of type Schema.SobjectField and is being attempted to be stored in a variable of type of String which is not permitted.
Id cid = network.Id;
sam_Adminsam_Admin
I tried that and it still throws error Illegal assignment from Schema.SObjectField to Id at line 13 column 12
sam_Adminsam_Admin
I have updaed my previous code so it doesn't hit DML limits, below is the code, is it possible to incude contact piece to it?

Trigger AutoforwardOpp on Opportunity(before insert, before update)
{
    String UserName = UserInfo.getName();
    String orgName = UserInfo.getOrganizationName();
    List<PartnerNetworkRecordConnection> AcctConnectionList = new List<PartnerNetworkRecordConnection>();
    List<PartnerNetworkRecordConnection> OpptyConnectionList = new List<PartnerNetworkRecordConnection>();
    List<PartnerNetworkConnection> connMap = new List<PartnerNetworkConnection>
    ([select Id, ConnectionStatus, ConnectionName from PartnerNetworkConnection where ConnectionStatus = 'Accepted']);
    List<PartnerNetworkRecordConnection> prncList = new List<PartnerNetworkRecordConnection>();

    for(Integer i =0; i< Trigger.size; i++)
    {
        Opportunity opp = Trigger.new[i];
        String oId = opp.Id;
        String acctId = opp.AccountId;
        for(PartnerNetworkConnection network : connMap)
        {

            String cid = network.Id;
            String status = network.ConnectionStatus;
            String connName = network.ConnectionName;

            if(opp.FFCNSales_Department__c == 'US')
            {
                PartnerNetworkRecordConnection newrecord = new PartnerNetworkRecordConnection();
                newrecord.ConnectionId = cid;
                newrecord.LocalRecordId = oId;
                newrecord.SendClosedTasks = true;
                newrecord.SendOpenTasks = true;
                newrecord.SendEmails = true;
                System.debug('Inserting New Record'+newrecord);
                OpptyConnectionList.add(newrecord);

                PartnerNetworkRecordConnection newAcctRecord = new PartnerNetworkRecordConnection();
                newAcctRecord.ConnectionId = cid;
                newAcctRecord.LocalRecordId = acctId;
                newAcctRecord.SendClosedTasks = true;
                newAcctRecord.SendOpenTasks = true;
                newAcctRecord.SendEmails = true;
                System.debug('Inserting New Record'+newrecord);
                AcctConnectionList.add(newAcctRecord);
            }
        }
    }
    if(AcctConnectionList.size()>0){
         insert AcctConnectionList;
    }
    if(OpptyConnectionList.size()>0){
         insert OpptyConnectionList;
    }
}
jigarshahjigarshah
Sam,

The code is rectified and verified it at my end and it works as expected. This should work fine for you without any errors. Also, since the records are shared using a Salesforce to Salesforce connection, they should be done when the DML operations successfully commit their values to the database or else it might result in inconistency. Hence I have changed the trigger to fire on After Insert and After Update events.
 
Trigger AutoforwardOpp on Opportunity(after insert, after update)
{
	List <PartnerNetworkRecordConnection> prncList;
	List <PartnerNetworkConnection> connectionList;
	Map <ID, PartnerNetworkConnection> connMap;
	Map <ID, ID> oppIdvsAccountIdMap;
	Map<ID, Account> accountWithContactMap;
    
    ID cid;
	String status;
	String connName;

	if(Trigger.isAfter && (Trigger.isInsert || Trigger.isUpdate)){
			
		connectionList = new List<PartnerNetworkConnection>();
		prncList = new List<PartnerNetworkRecordConnection>();
		
		//This would ideally return multiple active Connections if they exist hence its best you use a 
		//criteria to ensure only the appropriate connection record is returned. 
		connMap = new Map<ID, PartnerNetworkConnection>(
			[Select ID, ConnectionStatus, ConnectionName 
			 From PartnerNetworkConnection 
			 Where ConnectionStatus = 'Accepted']);
		
		//get connection details		
		for(ID connId :connMap.keySet()){
			cid = connMap.get(connId).ID;
            status = connMap.get(connId).ConnectionStatus;
            connName = connMap.get(connId).ConnectionName;
		}
		
		//Populate a map of Opp Ids and associated Account Ids
		oppIdvsAccountIdMap = new Map<ID, ID>();
		for(Opportunity oppRecord :Trigger.new){
		
			if(oppRecord.Department__c == 'US'){
					oppIdvsAccountIdMap.put(oppRecord.ID, oppRecord.Account.ID);
			}
		}
		
		//Get associated Accounts and Contacts for every US opportunity if they exist
		if(oppIdvsAccountIdMap.keySet().size() > 0){
		
			accountWithContactMap = new Map<ID, Account>(
				[Select ID, Name,
					(Select ID, Name From Account.Contacts)
				 From Account
				 Where ID IN :oppIdvsAccountIdMap.values()]);

			//Create PartnerNetworkRecordConnections for sharing the records
			for(ID oppId : oppIdvsAccountIdMap.keySet()){
			
				ID accountId = oppIdvsAccountIdMap.get(oppId);
				
				//Share Opportunity
				prncList.add(new PartnerNetworkRecordConnection(
					ConnectionId = cid,
					LocalRecordId = oppId,
					SendClosedTasks = true,
					SendOpenTasks = true,
					SendEmails = true));
				
				//Share Account
				if(oppIdvsAccountIdMap.get(oppId) != null){
				
					prncList.add(new PartnerNetworkRecordConnection(
                        ConnectionId = cid,
                        LocalRecordId = accountId,
                        SendClosedTasks = true,
                        SendOpenTasks = true,
                        SendEmails = true));
				}
				
				//Share associated Contacts
				if(accountWithContactMap.get(accountId).Contacts != null){
				
					for(Contact contact :accountWithContactMap.get(accountId).Contacts){
					
						prncList.add(new PartnerNetworkRecordConnection(
							ConnectionId = cid,
							LocalRecordId = contact.ID,
							SendClosedTasks = true,
							SendOpenTasks = true,
							SendEmails = true));
					}
				}
			}//for
			
			//Insert record conneections
			if(!prncList.isEmpty()){
			
				try{
					insert prncList;
				}
				catch(System.Dmlexception dmlExceptionInstance){
					System.debug('Record Share Error:' + dmlExceptionInstance.getMessage());
				}
			}
		}//if
	}
}
Please do not forget to mark this thread as SOLVED and answer as the BEST ANSWER if it helps resolve your issue.
This was selected as the best answer
sam_Adminsam_Admin
Thanks Shah, i was able to save the code but when i update the existing record and set the department to "US" i get the error "Apex trigger AutoforwardOpp caused an unexpected exception, contact your administrator: AutoforwardOpp: execution of AfterUpdate caused by: System.NullPointerException: Attempt to de-reference a null object: Trigger.AutoforwardOpp: line 83, column 1".

I changed it to before insert but still get same error, any idea why?
jigarshahjigarshah
Sam,

This has been fixed. Line # 37 was updated to as shown below. 
oppIdvsAccountIdMap.put(oppRecord.ID, oppRecord.AccountId);
Please do not forget to mark this thread as SOLVED and answer as the BEST ANSWER if it helps resolve your issue.
jigarshahjigarshah
Just found this documentation (https://help.salesforce.com/articleView?id=business_network_assign_related_tasks.htm&type=0)which says "Child records are automatically shared with connections after the parent record has been accepted by the connection, provided certain criteria are met."

You might want to try inserting the Account records first and I believe the Opportunity and Contact records should be shared auotmatically. Try and let me know.