Tuesday 3 February 2015

Capturing and Storing Case Resolution Fields in The Case Form

Recently I had this question from the Community fellows and I think there are many people also need this requirement since you know this is very difficult to display the fields from the Case Resolution. They are stored in the different entity and included as Activity entity which is considered as Child record to the Case so that you cannot show the fields value as the displayed column through View or Advanced Find.

Let’s get started..

Objective

Our objective here is to capture the information that User Inputted through this system form and store the values to the Case entity.

image

Create Fields in the Case Entity

Now, I create the fields that I need in the Case entity

- Resolution
- Total Time
- Billable Time
- Remarks

*Resolution Type is already defined in the Status Reason of the Case, in case you want to create new field, it is also possible to do!

What If I Want To Have Another Status Code?

You can go to Status Reason field of the Case entity and Add New Item

*Status Reason Field

image

I create a new item: ‘Enhancement Requested’

Then I put those fields in the Form and make them as read-only

image

Problem

The challenge here is this entity is a special Entity that seems to be ‘hidden’ in CRM and included as Activity in CRM, thus, considered as Child record of the Case, we should take note on that list to make the proper solution.

Solution

Of course as the Consultant we need to give the best solution and the best solution that comes up to the CRM professional is thinking the Out of the box first or the most effortless customization if inbuilt function is not there, Should I create Workflow or Plugin?

#1 Can I use Workflow for Case Resolution?

The answer is ‘No’ because the Case Resolution is one of the unsupported entity in Workflow.

#2 Can I use the Workflow and use The Case as The Entity?

Okay if you are using the OOB Workflow, the answer is ‘No’ as the solution here, it is not possible because as mentioned before Case Resolution is a child entity, as we know the OOB Workflow cannot get the related record from the 1:N Relationship so you cannot get the Case Resolution entity record through parent Case using Out of The Box CRM Workflow

#3 Can I use Plugin?

Yes, of course, but what kind of Plugin?

#4 What about Plugin on The Case Resolution Entity?

Surprisingly it works! I tried it.

I thought it would not work if I register to the Case Resolution entity on Post-Create Event because at the time Case Resolution Entity is created by the time the Case has been Resolved (status that makes the Case Read-Only).

After some research I see that in the Case the status is still 1 or In Progress

image

image

This is possible because CRM has another message Close for Case Entity.

#5 What is the difficulty?

The difficulty here is to retrieve the Total Time here because you need to sum up the times spent in each activity related to the Case.

image

Another difficulty here is to get the Status Code to become the Resolution Type because mentioned before CRM only gives status = 1 (In Progress) not yet Resolved, so that you might need another plugin in the Case entity to capture that, but I recommend you to use the Status Reason field in the Case entity. I you really need this field you can contact me for further development.

#6 So, What Is The Plugin Code?

Here is the Plugin Code

public class CaseResolution : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            #region must to have

            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

            IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

            // Create service with context of current user
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

            //create tracing service
            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

            #endregion

            #region Variable

            Entity targetCase = new Entity("incident");
            string strResolution = string.Empty;
            int intTotalTime = -1;
            int intTotalBillableTime = -1;
            string strRemarks = string.Empty;

            #endregion

            if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
            {

                //create entity context
                Entity entity = (Entity)context.InputParameters["Target"];

                if (entity.LogicalName != "incidentresolution")
                    return;

                try
                {
                    if (entity.Contains("incidentid"))
                    {
                        //get the related Case
                        targetCase.Id = ((EntityReference)entity["incidentid"]).Id;
                        
                        //capture the Case Resolution Fields                      
                        strResolution = entity.Contains("subject") ? entity["subject"].ToString() : string.Empty;
                        intTotalBillableTime = entity.Contains("timespent") ? (Int32)entity["timespent"] : 0;   
                        strRemarks = entity.Contains("description") ? 
                            (entity["description"] != null ? entity["description"].ToString() : string.Empty) : 
                            string.Empty;

                        //get the total time from Activities
                        intTotalTime = GetTotalTime(service, targetCase.Id);
                        
                        //update Case with the fields
                        targetCase["new_resolution"] = strResolution;
                        targetCase["new_totalbillabletime"] = intTotalBillableTime;
                        targetCase["new_totaltime"] = intTotalTime;
                        targetCase["new_remark"] = strRemarks;
                        service.Update(targetCase);
                    }
                }
                catch (Exception ex)
                {
                    throw new InvalidPluginExecutionException(ex.Message);
                }

            }
        }

        private int GetTotalTime(IOrganizationService service, Guid guidRelatedCaseId)
        {
            //count the Activity Actual Duration Minutes for this Case
            //need to sum time spent of each activity (cannot directly using the actualtdurationminutes) 

            int intSumTotalTime = 0;

            //Retrieve all related Activities by Case
            QueryExpression query = new QueryExpression("activitypointer");
            query.ColumnSet.AddColumns("actualdurationminutes");

            query.Criteria = new FilterExpression();
            query.Criteria.AddCondition("regardingobjectid", ConditionOperator.Equal, guidRelatedCaseId);

            // Execute the Query 
            EntityCollection results = service.RetrieveMultiple(query);

            foreach (Entity entity in results.Entities)
            {
                int intActivityTime = 0;
                intActivityTime = entity.Contains("actualdurationminutes") ? (Int32)entity["actualdurationminutes"] : 0;
                intSumTotalTime = intSumTotalTime + intActivityTime;
            }

            return intSumTotalTime;
        }
    }

#5 How to Register The Plugin


Here is the Plugin Registration Tool Setting for this Step

image

Result


And Here is your Result

I resolve the Case with following information

image

And here is the captured Information in my Case entity form.

image

Summary

Here is the summary

1. You cannot capture using the Out of the box Workflow because the entity is not supported

2. You can achieve it by creating a plugin updating the Case fields and register the plugin on the Post-Create of the Incident Resolution entity

3. Just be careful, in CRM a case can be closed and can be-reactivated again so every time CRM close the case it will keep updating the field and keep the latest position/value and will create another activity-close case to the related Case

image

This is how CRM treats the Case Resolution as the Case Activities.

4. CRM stores the total billable time in the 'Time Spent' field, while the Total Time for all activities are not stored in any field, you need to manually count the SUM from each related Case Activities, then store it somewhere else if you want to display it.

5. Once you save those fields in the Case, you will able to see the fields in the Case entity, either through Form, View, or Report of Case entity, while if you are not, you can still show but you need to query agains the Activity entity with type = Case Resolution.

Hope this helps you!

Thank you.

17 comments:

  1. hi, great work. how do you get the resolved case results onto the case form? kindly assist

    ReplyDelete
  2. Good solution!
    Do you know how to bring a custom field value(text) to Remarks from the case to the case resolution form when you resolve the case?
    Thanks
    :)

    ReplyDelete
  3. Nice Sharing! I like this topic.This site has lots of advantage.I found many interesting things from this site. It helps me in many ways.Thanks for posting this again. Thanks a million and please keep up the effective work Thank yo so much for sharing this kind of info- CRM development company

    ReplyDelete
  4. This is great! Do you have any idea how to resolve a case and just auto populate the resolution field with the word "Resolved" - or to even just not see the case resolution screen when you select the "resolve case" button? Any suggestions would be greatly appreciated. Thanks!

    ReplyDelete
  5. Hi Buddy,

    Nicely Done.
    I am learning CRM and the next task I m trying is to update a custom entity Resolution field with Case Resolution whenever the case is resolved.
    Can you please help me with the same.

    ReplyDelete
  6. Hi,
    I am trying to understand on how to generate SLAs per queue and globally (when transferred to other queue ) for a case. (ie, new case opened and assigned to a queue A, case is then transferred to queue B. I would like to know the total time that queue A had the case and total time queue B had the case and the grand total of the case from open to resolved.

    Will your 4 & 5 point help me in this?

    Regards,
    Ganesh A

    ReplyDelete
  7. You are a genius! I have been able to achieve this with not programing knowledge whatsoever!

    Thank you so much!!

    Yvan

    ReplyDelete
  8. hi sir ,, i want to get the time spend between created on date and resolve date of case ...how can do this even you know after case resolve we cannot update any field on case

    ReplyDelete
  9. Lots of Good information in your post, I favorited your blog post so I can visit again in the future, Thanks.

    business expense tracker

    ReplyDelete
  10. You can use this cloud service https://web2case.com to capture customer incidents directly into your Dynamics CRM

    ReplyDelete
  11. Get Data Capture definition and information from here Data Capture Form

    ReplyDelete
  12. This is still relevant and still works (Dynamics CRM online v9.1) -- thank you so much!!

    ReplyDelete
    Replies
    1. Hi BDCDebbie,

      Yes your correct it's worked for resolution filed only. billable time not working my case. Kindly help me.

      Delete
  13. Hello to all.
    If you want to prevent the user from closing a case with a certain value in the type of case resolution, you can register in the onPreCreate for incidentresolution entity, one plugin that checks the values that are reported by the incidentresolution entity, with something like this:

    int InValue = 0;
    if (context.ParentContext.ParentContext.PrimaryEntityName == "incident")
    {
    ParameterCollection valS = (ParameterCollection)context.ParentContext.ParentContext.InputParameters;
    foreach(var v in valS)
    {
    if ((string)v.Key.ToLower() == "status")
    {
    InValue = ((OptionSetValue)v.Value).Value;
    }
    }
    }
    if (inValue != goodValueForMyRequirements)
    {
    throw new InvalidPluginExecutionException("You enter a invalid status reason for this incident.");

    }

    Hope this helps.
    Regards,

    ReplyDelete
  14. I have tired the above plug in sandbox instance getting below business error.where I need to design form in case entity or case resolution entity kindly help me for this.

    'incident' entity doesn't contain attribute with Name = 'new_totalbillabletime' and NameMapping = 'Logical'.

    if it is possible to store resolution in resolved form.

    ReplyDelete

My Name is..