[SalesForce] Adding Contacts to Campaign as Campaign Members

I have a scenario where Contacts are being fed(upsert operation) from a third party application. Along with the Contact information, contact has an External Id for campaign. If a contact is updated, I need to first check if the contact is already a Campaign member of that campaign. If not add a new campaign member otherwise update the campaign member. It sounds to me like an upsert operation. Following is the logic I am using.

Here I am building a map of campaigns and Campaign external ID, where UTMCampaignID is a set of all campaign external id's fed from third party.

           //building a set of campaigns belonging to contact's UTMCmapaign Id
            List<Campaign> ExpenseCampaignList = [select Id, UtmCampaign_ID__c 
                                                    from Campaign
                                                    where UtmCampaign_ID__c in :UTMCampaignId];

            //building a map of campiagns and UTMCampaign ID
            map<string, Campaign> ExpenseCampaignMap = new map <string, Campaign>();
            for(Campaign c : ExpenseCampaignList)
            {   
                ExpenseCampaignMap.put(c.UtmCampaign_ID__c, c);
            }

In order to upsert campaign members, I am creating a new instance of campaign members and assigning an external id to them, which is nothing but concatenation of Campaign ID and Contact ID.

           list<CampaignMember> newCampaignMembersExpCamp = new list<CampaignMember>();
           Campaign UTMCampaign;
            for(Contact con: trigger.new)
                {

                    UTMCampaign = ExpenseCampaignMap.get(con.utmcampaign__c);
                    string ExternalCampaingID = UTMCampaign.Id;
                    ExternalCampaingID += con.Id;
                    CampaignMember cm= New CampaignMember(CampaignId=UTMCampaign.Id, ContactId= con.Id , Status='Opt-In',External_ID__c = ExternalCampaingID);
                    newCampaignMembersExpCamp.add(cm);
                }
            upsert newCampaignMembersExpCamp External_ID__c;

The above code works fine for a new campaign member, however if campaign member already exist, the code errors out. Following is the error message.

Review all error messages below to correct your data.
Apex trigger contactTrigger caused an unexpected exception, contact your administrator:
contactTrigger: execution of AfterUpdate caused by: System.DmlException: Upsert failed.  
First exception on row 0; first error: INVALID_FIELD_FOR_INSERT_UPDATE, 
Unable to create/update fields: ContactId. Please check the security settings of this  
field and verify that it is read/write for your profile or permission set.: 
[ContactId]: Trigger.contactTrigger: line 67, column 1

Best Answer

An upsert allows the DML operation to choose between an "insert" and an "update" operation. If a record already exists, it updates it. If the record is new, or doesn't already exist, it inserts it.

In your situation, if the record already exists and there are no changes to it, then you don't need to update it. You only need to insert new records. I don't see a check in your trigger above to see if the contact is already a member of the campaign. It appears to me that once you've assembled the external Id's, you need to query to see if any of them exist and remove them from your list.

First exception on row 0; first error: INVALID_FIELD_FOR_INSERT_UPDATE, Unable to create/update fields: ContactId. Please check the security settings of this
field and verify that it is read/write for your profile or permission set.: [ContactId]: Trigger.contactTrigger: line 67, column 1

The above tells you the problem begins someplace within line 67 of your code and relates to the ContactId.

Since I can't tell if you've posted all of your code or what the line numbers are, based on what you've posted, I'm guessing the problem lies with this line:

CampaignMember cm= New CampaignMember(CampaignId=UTMCampaign.Id, ContactId= con.Id, Status='Opt-In',External_ID__c = ExternalCampaingID); 

It appears to me the error is telling you that the contact Id already exists in your database for that External_ID__c.

Related Topic