CRM 2011 Convert Activity to Case - Populate Case Details
When converting an activity (such as Phone Call) to case, we can only specify the Customer and the Subject on the popup dialog. What if we want to auto-populate the case details with the information from the activity?
At first I thought we can write a plugin that triggers on the post-create of a case. However this is not possible since CRM creates the Case before it sets the Regarding field on the Activity.
The workaround for this is to create the post-update plugin on the Activity itself. This way when the Regarding field is assigned by CRM, it will look for the Case and update its details.
Be careful though because this might not work when converting Activity to Case from Outlook. I read somewhere that when converting Email to Outlook, the Regarding field is set to the Parent Customer of the Case rather than the Case itself.
Hope this helps,
Andreas
At first I thought we can write a plugin that triggers on the post-create of a case. However this is not possible since CRM creates the Case before it sets the Regarding field on the Activity.
The workaround for this is to create the post-update plugin on the Activity itself. This way when the Regarding field is assigned by CRM, it will look for the Case and update its details.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Xrm.Sdk; using Microsoft.Xrm.Sdk.Messages; using System.ServiceModel; using Org.Entities.Crm; namespace Org.Crm.Plugins { /// <summary> /// This plugin is intended to: /// 1. Hook up to post-update message of phone call entity. /// Update Case Details if any /// </summary> public class PhoneCallUpdateCaseDetails : IPlugin { ITracingService tracingService = null ; public void Execute(IServiceProvider serviceProvider) { // Extract the tracing service. tracingService = (ITracingService)serviceProvider.GetService( typeof (ITracingService)); if (tracingService == null ) throw new InvalidPluginExecutionException( "Failed to retrieve the tracing service." ); // Obtain the execution context from the service provider. IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService( typeof (IPluginExecutionContext)); // The InputParameters collection contains all the data passed in the message request. if (context.InputParameters.Contains( "Target" ) && context.InputParameters[ "Target" ] is Entity) { // Obtain the target entity from the input parameters. Entity entity = (Entity)context.InputParameters[ "Target" ]; // Get a reference to the Organization service. IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService( typeof (IOrganizationServiceFactory)); IOrganizationService service = factory.CreateOrganizationService(context.UserId); try { // Plug-in business logic goes below this line. // Invoke organization service methods. #if DEBUG tracingService.Trace( "{0} Plugin started." , this .GetType().Name); #endif OrgServiceContext serviceContext = new OrgServiceContext (service); PhoneCall retrievedPhoneCall = serviceContext.PhoneCallSet.Where(x => x.Id == entity.Id).SingleOrDefault(); if (retrievedPhoneCall.RegardingObjectId != null ) { PopulateDetails(retrievedPhoneCall, serviceContext, tracingService); } #if DEBUG tracingService.Trace( "{0} Plugin completed." , this .GetType().Name); #endif } catch (InvalidPluginExecutionException iex) { tracingService.Trace(iex.Message); tracingService.Trace(iex.StackTrace); throw iex; } catch (FaultException<organizationservicefault> ex) { tracingService.Trace(ex.Message); tracingService.Trace(ex.StackTrace); throw new InvalidPluginExecutionException( string .Format( "An error occurred in the {0} plug-in." , this .GetType().Name), ex); } catch (Exception e) { tracingService.Trace(e.Message); tracingService.Trace(e.StackTrace); throw new InvalidPluginExecutionException( string .Format( "An error occurred in the {0} plug-in." , this .GetType().Name), e); } } } /// <summary> /// Populate Details /// </summary> private void PopulateDetails(PhoneCall retrievedPhoneCall, OrgServiceContext serviceContext, ITracingService tracingService) { Incident incident = serviceContext.IncidentSet.Where(c => c.Id == retrievedPhoneCall.RegardingObjectId.Id).SingleOrDefault(); if (incident != null ) { var phoneCalls = serviceContext.PhoneCallSet.Where(p => p.RegardingObjectId == new EntityReference(incident.LogicalName, incident.Id)).ToList(); //check if this is the first time creation if (phoneCalls.Count <= 1) { incident.Title = retrievedPhoneCall.Subject; incident.new_accountid = retrievedPhoneCall.new_accountid == null ? null : retrievedPhoneCall.new_accountid; incident.new_accountnumber = String.IsNullOrEmpty(retrievedPhoneCall.new_accountnumber) ? null : retrievedPhoneCall.new_accountnumber; incident.CustomerId = retrievedPhoneCall.From.FirstOrDefault().PartyId; incident.CaseOriginCode = new OptionSetValue(1); serviceContext.UpdateObject(incident); serviceContext.SaveChanges(); } } } } } |
Be careful though because this might not work when converting Activity to Case from Outlook. I read somewhere that when converting Email to Outlook, the Regarding field is set to the Parent Customer of the Case rather than the Case itself.
Hope this helps,
Andreas
hey good work
ReplyDeletecan i use this code and change it to work for me when am converting an email from the queue into a case...so that the case description picks up the email content??
and if its possible give me some guidelines ..am new with CRM 2011
Hi,
Deleteyou should be able to do the same with the email. When the email is converted to a case then the email regarding field will be set to that case.
So using the same approach as the above, you can grab the case (from the regarding field) in the post create plugin of the email and populate its fields.
The other approach that people have used is to create a custom workflow that checks the emails directed to a queue and create the case. This is not using the standard Convert button. However workflow jobs can be expensive and it's dependent on async service so I tend to go with plugin whenever possible.
HTH,
Andreas
Hi,
ReplyDeleteI am new to CRM and find your post helpful.
One point that I could not understand is why the plugin needs to be registered on post-update event of Activity itself. Though you have given some explanation but that I am unable to understand. Could you please elaborate some more.
Thanks
Rajesh
Hi Rajesh,
DeleteSure. What we want is to populate the some of the Case details from the Activity. For this to happen, you would need to know which Activity it is related to (of course :) )
As I mentioned before, CRM creates the case before it sets the 'Regarding' field. If we were about to do it on the Case plugin, then the 'relationship' is not established yet and we would not be able to know which Activity it is related to.
Therefore we do it on the Activity plugin, because when the 'Regarding' field is set by CRM, the plugin will get triggered and we will then populate the case details.
Hope this makes a bit clearer,
Andreas
hi,
ReplyDeletei'm looking for Org.Entities.Crm; in vs 2010 but there isn't any dll or class in this type
can you give me this?
or how can i get it?
the PhoneCall Method that you used in this application has not been found and need this dll i think!
if you can send it to me or put it in this page
my email address is: kzi.afshin@gmail.com
Thanks
Afshin