Customer Portal - error closing case w/open activities

Sep 12, 2010 at 7:38 AM

I am testing the Customer Portal Accelerator and am a newbie to the Dynamics CRM product.  Deployment is On-Premise w/IFD.

I have run into a problem where I get a "page not found" when trying to close a case via the customer portal.  This only happens when there is an open activity against the case.  I notice the documentation says that closing the case will automatically close any open activities so obviously this must be a clue to the issue.

I downloaded Fiddler figuring it would be helpful in determing the problem but am not sure what I should post from the tools' results that may help someone in answering this question.

Thanks in advance

Sep 21, 2010 at 5:46 AM

Still looking for some help on this one guys.  Anybody?

Sep 21, 2010 at 4:29 PM

Hi thielmag,

There is code in the "EditCase.aspx.cs" file on line 157 that closes off any tasks that could be related to the case (ex - phone call, task, fax, email, letter, appointment and service appointment). 

        protected void CloseRelatedActivities()
        {
            var coreContext = new CoreDataContext();
            var activities = Case.Incident_ActivityPointers;


            foreach (var a in activities)
            {
                if (a.statecode == "Open" || a.statecode == "Scheduled")
                {
                    var activityGuid = a.activityid;
                    var activityTypeCode = a.activitytypecode;

                    var xrm = new XrmDataContext();
                    var entityStatus = new EntityStatus();

                    switch (activityTypeCode)
                    {
                        case "phonecall":
                            var phonecall = xrm.phonecalls.Where(pc => pc.activityid == activityGuid).FirstOrDefault();
                            entityStatus.SetCallStatusAndSave(phonecall, "canceled");
                            break;

                        case "task":
                            var task = xrm.tasks.Where(t => t.activityid == activityGuid).FirstOrDefault();
                            entityStatus.SetTaskStatusAndSave(task, "canceled");
                            break;

                        case "fax":
                            var fax = xrm.faxes.Where(f => f.activityid == activityGuid).FirstOrDefault();
                            entityStatus.SetFaxStatusAndSave(fax, "canceled");
                            break;

                        case "email":
                            var email = xrm.emails.Where(e => e.activityid == activityGuid).FirstOrDefault();
                            entityStatus.SetEmailStatusAndSave(email, "canceled");
                            break;

                        case "letter":
                            var letter = xrm.letters.Where(l => l.activityid == activityGuid).FirstOrDefault();
                            entityStatus.SetLetterStatusAndSave(letter, "canceled");
                            break;

                        case "appointment":
                            var appointment = xrm.appointments.Where(ap => ap.activityid == activityGuid).FirstOrDefault();
                            entityStatus.SetAppointmentStatusAndSave(appointment, "canceled");
                            break;

                        case "serviceappointment":
                            var serviceAct = xrm.serviceappointments.Where(s => s.activityid == activityGuid).FirstOrDefault();
                            coreContext.SetActivityStatusAndSave(serviceAct, "canceled");
                            break;

                        default:
                            break;
                    }
                   
                }
            }

            return;
        }

 

 It would help me to know what type of activity you have open when this problem occurs so that I can replicate it.

Thanks!
Christine

Sep 23, 2010 at 4:59 AM

Christine,

I have tested by having the following open activities (one at a time): Task, Phone Call, and Letter.  as soon as these activities are "completed" then closing the case from the web interface as the customer works fine.  Otherwise, I get a 500 internal server error "page not displayed" error.  i could probably go on and test every other type of activity but I guess they will all do this.

If you cannot replicate, how do I go about debugging the code.  I have used VStudio for a long time but this CRM stuff is new to me and I'm guessing I can't just run a local copy on my desktop and have it work in debug mode.  Not sure though.  Could use some help there if you have no answers with the info given above.

Thanks for your time.

Gary

Sep 23, 2010 at 5:50 AM

Christine,

 

I jumped the gun a little when I replied.  I didn't even think to look at the .cs file you were referencing.  Turns out I don't even have that code for the CloseRelatedActivities in there.  I just downloaded the Portal about 4 weeks ago so I think I have the latest.

In any case (no pun intended here), I added your code, added "CloseRelated Activities();" to the ResolveButton_Click event then rebuild the solution.  Now I am getting errors on a portion of your code that thinks I am missing a reference to something:

Error 2 The type or namespace name 'EntityStatus' could not be found (are you missing a using directive or an assembly reference?) C:\websites\Customer-Portal-R2\Website\Pages\eService\EditCase.aspx.cs 169 44 Customer-Portal-R2

Then there are a bunch of errors referencing:

Error 3 'System.Linq.IQueryable<Xrm.phonecall>' does not contain a definition for 'Where' and no extension method 'Where' accepting a first argument of type 'System.Linq.IQueryable<Xrm.phonecall>' could be found (are you missing a using directive or an assembly reference?) C:\websites\Customer-Portal-R2\Website\Pages\eService\EditCase.aspx.cs 174 60 Customer-Portal-R2

Not sure what I am missing.  All my references seem okay.  I have the following "using" statement at top of EditCase.aspx.cs:
using System;
using Microsoft.Xrm.Portal.Access;
using Microsoft.Xrm.Portal.Core;
using Site.Library;
using Xrm;
using Microsoft.Xrm.Portal.Web;

None of them show errors and my XRM reference seems valid too.

Any ideas?

Sep 30, 2010 at 4:50 PM

Hi Gary...

Looks like you'll have to add a little more code to get this working.

Please create a class called "EntityStatus.cs" inside the Library folder.  Add the following code to this class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Xrm.Portal.Data.Services;
using Microsoft.Crm.Sdk;
using Microsoft.Xrm.Client.Services;
using Microsoft.Xrm.Client;

namespace Site.Library
{
    public class EntityStatus : DelegatedCrmDataContext
    {
		public EntityStatus() : base(null) { }

        /// <summary>
        /// Change the state of a PhoneCall.
        /// </summary>
        /// <param name="call">The Phone Call to change.</param>
        /// <param name="state">The state to change to.</param>
        /// <returns>The updated PhoneCall.</returns>
        /// <remarks>
        /// <para>The provided <paramref name="phonecall"/> must already be persisted to the CRM for this operation to succeed.</para>
        /// <para>It it not necessary to SaveChanges after this operation--this operation fully persists the state change to CRM.</para>
        /// </remarks>
        public ICrmEntity SetCallStatusAndSave(ICrmEntity call, string state)
        {
            call.AssertEntityName("phonecall");

            var result = TargetDataContext.UsingService(service => SetCallStatusAndSave(call, state, service));

            return result.ToCrmEntity();
        }

        private ICrmEntity SetCallStatusAndSave(ICrmEntity call, string state, IOrganizationService service)
        {
            var id = call.Id.Value;

            if (string.Compare(state, "Open", StringComparison.InvariantCultureIgnoreCase) == 0)
            {
                SetStateCall(service, PhoneCallState.Open, -1, id);
            }
            else // Canceled
            {
                SetStateCall(service, PhoneCallState.Canceled, -1, id);
            }

            return (service.Retrieve("phonecall", id) as DynamicEntity).ToCrmEntity(TargetDataContext);
        }


        public SetStatePhoneCallResponse SetStateCall(IOrganizationService service, SetStatePhoneCallRequest request)
        {
            return service.Execute<SetStatePhoneCallResponse>(request);
        }

        public void SetStateCall(IOrganizationService service, PhoneCallState callState, int callStatus, Guid entityId)
        {
            var request = new SetStatePhoneCallRequest { PhoneCallState = callState, PhoneCallStatus = callStatus, EntityId = entityId };
            SetStateCall(service, request);
        }

        /// <summary>
        /// Change the state of a Fax.
        /// </summary>
        /// <param name="fax">The Fax to change.</param>
        /// <param name="state">The state to change to.</param>
        /// <returns>The updated Fax.</returns>
        /// <remarks>
        /// <para>The provided <paramref name="fax"/> must already be persisted to the CRM for this operation to succeed.</para>
        /// <para>It it not necessary to SaveChanges after this operation--this operation fully persists the state change to CRM.</para>
        /// </remarks>
        public ICrmEntity SetFaxStatusAndSave(ICrmEntity fax, string state)
        {
            fax.AssertEntityName("fax");

            var result = TargetDataContext.UsingService(service => SetFaxStatusAndSave(fax, state, service));

            return result.ToCrmEntity();
        }

        private ICrmEntity SetFaxStatusAndSave(ICrmEntity fax, string state, IOrganizationService service)
        {
            var id = fax.Id.Value;

            if (string.Compare(state, "Open", StringComparison.InvariantCultureIgnoreCase) == 0)
            {
                SetStateFax(service, FaxState.Open, -1, id);
            }
            else // Canceled
            {
                SetStateFax(service, FaxState.Canceled, -1, id);
            }

            return (service.Retrieve("fax", id) as DynamicEntity).ToCrmEntity(TargetDataContext);
        }


        public SetStateFaxResponse SetStateFax(IOrganizationService service, SetStateFaxRequest request)
        {
            return service.Execute<SetStateFaxResponse>(request);
        }

        public void SetStateFax(IOrganizationService service, FaxState faxState, int faxStatus, Guid entityId)
        {
            var request = new SetStateFaxRequest { FaxState = faxState, FaxStatus = faxStatus, EntityId = entityId };
            SetStateFax(service, request);
        }

        /// <summary>
        /// Change the state of a Email.
        /// </summary>
        /// <param name="email">The Email to change.</param>
        /// <param name="state">The state to change to.</param>
        /// <returns>The updated Email.</returns>
        /// <remarks>
        /// <para>The provided <paramref name="email"/> must already be persisted to the CRM for this operation to succeed.</para>
        /// <para>It it not necessary to SaveChanges after this operation--this operation fully persists the state change to CRM.</para>
        /// </remarks>
        public ICrmEntity SetEmailStatusAndSave(ICrmEntity email, string state)
        {
            email.AssertEntityName("email");

            var result = TargetDataContext.UsingService(service => SetEmailStatusAndSave(email, state, service));

            return result.ToCrmEntity();
        }

        private ICrmEntity SetEmailStatusAndSave(ICrmEntity email, string state, IOrganizationService service)
        {
            var id = email.Id.Value;

            if (string.Compare(state, "Open", StringComparison.InvariantCultureIgnoreCase) == 0)
            {
                SetStateEmail(service, EmailState.Open, -1, id);
            }
            else // Canceled
            {
                SetStateEmail(service, EmailState.Canceled, -1, id);
            }

            return (service.Retrieve("email", id) as DynamicEntity).ToCrmEntity(TargetDataContext);
        }


        public SetStateEmailResponse SetStateEmail(IOrganizationService service, SetStateEmailRequest request)
        {
            return service.Execute<SetStateEmailResponse>(request);
        }

        public void SetStateEmail(IOrganizationService service, EmailState emailState, int emailStatus, Guid entityId)
        {
            var request = new SetStateEmailRequest { EmailState = emailState, EmailStatus = emailStatus, EntityId = entityId };
            SetStateEmail(service, request);
        }

        /// <summary>
        /// Change the state of a Letter.
        /// </summary>
        /// <param name="letter">The Letter to change.</param>
        /// <param name="state">The state to change to.</param>
        /// <returns>The updated Letter.</returns>
        /// <remarks>
        /// <para>The provided <paramref name="letter"/> must already be persisted to the CRM for this operation to succeed.</para>
        /// <para>It it not necessary to SaveChanges after this operation--this operation fully persists the state change to CRM.</para>
        /// </remarks>
        public ICrmEntity SetLetterStatusAndSave(ICrmEntity letter, string state)
        {
            letter.AssertEntityName("letter");

            var result = TargetDataContext.UsingService(service => SetLetterStatusAndSave(letter, state, service));

            return result.ToCrmEntity();
        }

        private ICrmEntity SetLetterStatusAndSave(ICrmEntity letter, string state, IOrganizationService service)
        {
            var id = letter.Id.Value;

            if (string.Compare(state, "Open", StringComparison.InvariantCultureIgnoreCase) == 0)
            {
                SetStateLetter(service, LetterState.Open, -1, id);
            }
            else // Canceled
            {
                SetStateLetter(service, LetterState.Canceled, -1, id);
            }

            return (service.Retrieve("letter", id) as DynamicEntity).ToCrmEntity(TargetDataContext);
        }


        public SetStateLetterResponse SetStateLetter(IOrganizationService service, SetStateLetterRequest request)
        {
            return service.Execute<SetStateLetterResponse>(request);
        }

        public void SetStateLetter(IOrganizationService service, LetterState letterState, int letterStatus, Guid entityId)
        {
            var request = new SetStateLetterRequest { LetterState = letterState, LetterStatus = letterStatus, EntityId = entityId };
            SetStateLetter(service, request);
        }

        /// <summary>
        /// Change the state of a Task.
        /// </summary>
        /// <param name="task">The Task to change.</param>
        /// <param name="state">The state to change to.</param>
        /// <returns>The updated Task.</returns>
        /// <remarks>
        /// <para>The provided <paramref name="task"/> must already be persisted to the CRM for this operation to succeed.</para>
        /// <para>It it not necessary to SaveChanges after this operation--this operation fully persists the state change to CRM.</para>
        /// </remarks>
        public ICrmEntity SetTaskStatusAndSave(ICrmEntity task, string state)
        {
            task.AssertEntityName("task");

            var result = TargetDataContext.UsingService(service => SetTaskStatusAndSave(task, state, service));

            return result.ToCrmEntity();
        }

        private ICrmEntity SetTaskStatusAndSave(ICrmEntity task, string state, IOrganizationService service)
        {
            var id = task.Id.Value;

            if (string.Compare(state, "Open", StringComparison.InvariantCultureIgnoreCase) == 0)
            {
                SetStateTask(service, TaskState.Open, -1, id);
            }
            else // Canceled
            {
                SetStateTask(service, TaskState.Canceled, -1, id);
            }

            return (service.Retrieve("task", id) as DynamicEntity).ToCrmEntity(TargetDataContext);
        }


        public SetStateTaskResponse SetStateTask(IOrganizationService service, SetStateTaskRequest request)
        {
            return service.Execute<SetStateTaskResponse>(request);
        }

        public void SetStateTask(IOrganizationService service, TaskState taskState, int taskStatus, Guid entityId)
        {
            var request = new SetStateTaskRequest { TaskState = taskState, TaskStatus = taskStatus, EntityId = entityId };
            SetStateTask(service, request);
        }

        /// Change the state of a Appointment.
        /// </summary>
        /// <param name="appointment">The Appointment to change.</param>
        /// <param name="state">The state to change to.</param>
        /// <returns>The updated Appointment.</returns>
        /// <remarks>
        /// <para>The provided <paramref name="appointment"/> must already be persisted to the CRM for this operation to succeed.</para>
        /// <para>It it not necessary to SaveChanges after this operation--this operation fully persists the state change to CRM.</para>
        /// </remarks>
        public ICrmEntity SetAppointmentStatusAndSave(ICrmEntity appointment, string state)
        {
            appointment.AssertEntityName("appointment");

            var result = TargetDataContext.UsingService(service => SetAppointmentStatusAndSave(appointment, state, service));

            return result.ToCrmEntity();
        }

        private ICrmEntity SetAppointmentStatusAndSave(ICrmEntity appointment, string state, IOrganizationService service)
        {
            var id = appointment.Id.Value;

            if (string.Compare(state, "Scheduled", StringComparison.InvariantCultureIgnoreCase) == 0)
            {
                SetStateAppointment(service, AppointmentState.Scheduled, -1, id);
            }
            else // Canceled
            {
                SetStateAppointment(service, AppointmentState.Canceled, -1, id);
            }

            return (service.Retrieve("appointment", id) as DynamicEntity).ToCrmEntity(TargetDataContext);
        }


        public SetStateAppointmentResponse SetStateAppointment(IOrganizationService service, SetStateAppointmentRequest request)
        {
            return service.Execute<SetStateAppointmentResponse>(request);
        }

        public void SetStateAppointment(IOrganizationService service, AppointmentState appointmentState, int appointmentStatus, Guid entityId)
        {
            var request = new SetStateAppointmentRequest { AppointmentState = appointmentState, AppointmentStatus = appointmentStatus, EntityId = entityId };
            SetStateAppointment(service, request);
        }
    }
}
This should get you going.  Let me know if you run into anymore issues.
Sep 30, 2010 at 4:57 PM

Thanks.  I appreciate your continued help on this.  BTW...I found out that this additional code is not in the Customer Portal but is in the Partner Portal. I also kinda figured out I was missing the Entity classes but still got stuck at some point.

 I will do what you suggest here and get back to you.