One of our clients is using auto numbering on contact records. A few days ago, they reported to have duplicates in the system. So I started the investigation, I could not believe that this could happen in our solution. But what I had found out was that those duplicates were generated as a part of the "Merge" functionality available in CRM. Every time users "Merge" the customer and choose the subordinate's customer number to come across, it will override the master record's customer number with the subordinate record's number.
So we decided to write a plugin that will stop the users from overriding the master record's customer number.
The context.InputParameters collection of the merge message contains 3 of the following objects
- Target ( entity reference of the master record)
- SubordinateId ( guid of the subordinate record)
- UpdateContent ( temporary entity that contains the attribute that will be passed to the master record).
The following example does not use the SubordinateId object. We are only using Target and UpdateContent entity. Like any other plugin entity, the "UpdateContent" entity only contains attributes that will be updated in the master record.
Code
protected void ExecutePreCustomerMerge(LocalPluginContext localContext) { if (localContext == null) { throw new ArgumentNullException("localContext"); } IPluginExecutionContext context = localContext.PluginExecutionContext; ITracingService trace = localContext.TracingService; IOrganizationService service = localContext.OrganizationService; // if the sdk message is merge if (context.MessageName.Equals("merge", StringComparison.InvariantCultureIgnoreCase)) { //get the merged entity Entity updateContentData = context.InputParameters["UpdateContent"] as Entity; //if the merged record is null then do nothing if (updateContentData == null) { return; } //get the customer number of merged record string mergedCustNumber = updateContentData.GetAttributeValue<string>("custNumber"); if (mergedCustNumber == null) return; else { // if the merged CustNumber is not null retrieve the CustNumber of the master record to display in the message // get the master entity reference EntityReference targetReference = (EntityReference)context.InputParameters["Target"]; //trace.Trace("entity reference " + targetReference.LogicalName.ToString()); //retrieve the CustNumber number of the master entity Entity target = service.Retrieve(targetReference.LogicalName, targetReference.Id, new ColumnSet("custNumber")); string masterCustNumber = target.GetAttributeValue<string>("custNumber"); throw new InvalidPluginExecutionException("You cannot update the CustNumber of the Master record. Master CustNumber :" + masterCustNumber + " and New CustNumber :" + mergedCustNumber); } } }
Some Other Observations
When I tested this plugin in CRM2013 roll up 2, I did not receive the message thrown using InvalidPuginExecutionException. Instead, I received the following message:
I think it is a bug in CRM2013, that is now fixed in CRM2013 SP1.
When I tested the same plugin on CRM2013 SP1 UR3, It displays the proper message, as thrown by the InvalidPuginExecutionException.
Great blog Amreek. Very informative.
ReplyDeleteI have 2 questions... Do we have access to preimage in this plugin message. If yes would it point to the Target or the Subordinate. I assume it will be the Target and based on that it might eliminate the need for the second Web service call to retrieve the masterCustNum from the target.
Second question: if I remove the custNum from the UpdateContent record, would it not override the master number? I'm thinking about rather than I display an error, I'd allow the process to go through but the plugin will prevent the master number from being overridden.
I'm asking these because I'll need to implement this functionality. Thanks to your code, will make my life easier.
According to the Microsoft documentation, pre and post images are available for both target and subordinate records. I have not tried myself yet.
ReplyDeletehttps://msdn.microsoft.com/en-au/library/gg309673.aspx
Second question:Yes you are correct. According to my requirements, I have to display the error message.The CRM customers in my scenario also have external portal access. The user may need to make the changes to the existing records before merging them.
Thanks for the response. The sdk article really helped. Cheers.
DeleteThis comment has been removed by the author.
Delete2 years later and this is still a great post. I have one question. Did you create a pre- or post step to trigger the plugin? I've been trying pre-operation, but the Target is null.
ReplyDeleteHave you ever considered about adding a little bit more than just your articles?
ReplyDeletethe app developers