CRM 2011/2013 – What security roles do you to need to run a dialog

I had a curious question today, what security roles do you need to run a dialog?  It was one of those questions that just stopped me in my tracks, I had no idea.

One interesting thing I noticed is security roles do not need to be published, they take affect as soon as you press the save button.  This is good know but also I’m sure sometimes they weren’t always taking effect.

 

Dialog’s are like workflows?

I assumed Dialogs were the same as workflows and some of the security was set in the scope of the workflow.  You can read about Workflow security in this great blog by Richard Knudson – Security for CRM 2011 Automatic Processes

For workflows you set the scope inside the workflow and then the user will need the Execute Workflow job security role

 

Dialog’s security is different

There is no scope in Dialog’s, as you can see by the screenshot below

dialogs security needed 2

 

So the first problem I had the user couldn’t see the Dialog and this is a major problem when they want to run it.  What I mean is the user could select the correct entity – contact but when they pressed the dialog button it show now available dialogs to run.

So the first  change I did was to give organisational privilege for Process – Read Priviege

dialogs security needed 0

The user could now see the dialog but when I tried to run it, in the words of the Lemonhead’s I got the great big no

dialogs security needed 1

So I then added some Dialog session privileges Create, Read, Write and I was still getting the error above.

I was thinking, maybe’s it’s the append, appendTo privilege because you often need to append and appendto.  I added on those two security privileges at organisational level and it worked, hazaar.

dialogs security needed 3

 

It took some trail and error testing but I finally got there, it was the sneaky process and Append, AppendTo privileges.

 

This is usually the time the person sitting next to you says he knew that and I should have just asked him

 

CRM 2011/2013 Dialog’s and Custom Workflow example

I had piece of functionality I did at work recently and it had a few interesting parts, so I thought I would blog it down.  You can read the blog or watch the video

The required functionality required the ability to update multiple appointments, in this deployment we have created a new appointment entity called Client appointment but basically I needed to update multiple appointments.

The user wanted to specify a cancellation reason.

I was initial thinking of using a workflow and selecting lots of appointments but because they needed to specify a cancellation reason then this wasn’t an option

With input required a dialog seemed like a good option.

The problem I quickly found was Dialog’s can only be triggered on one record at a time and not multiple records like workflows.

Contact Dialog

So the plan was changed to be run on the contact.  I would have a dialog which ran on the contact entity the user would be prompted for a start date, end date and a cancellation reason.

I would call a Custom Workflow from with the dialog and pass selected values to it and then the custom workflow would do a query, select all the appointments, cancel them and then create a reschedule task and assign it to a reschedule queue.

I usually trigger code changes from plugins and wondered what circumstances would I move that code to be triggered into a Custom Workflow but this a good example.

This code isn’t really suitable to be triggered from a plugin because there isn’t anything being changed/updated or created so there is no natural plugin trigger point.

Thinking about this I can see that within certain workflows and dialog’s is the perfect place to call a custom workflow, particularly when nothing has been updated or modified and you want to trigger those changes and the changes are going to be complex which needs a code to do.  This is a good example because the code needs to retrieve a lot of appointments linked to a contact, this functionality couldn’t be achieved in workflow or definitely not easily.

After re-reading the requirements I noticed we needed to specify a start time and end time and this would also work in a slightly unusual manner.  If the user specified 08:00 to 12:00 with a start date and end date which went over more than one day.  The user wanted the morning appointments to be cancelled for each day specified but the afternoon appointments to be left alone.  This would provide a tricky piece of querying which I will go into later.

In theory this seemed like it would work, so I initially created a skeleton Dialog and a Custom workflow which logged the fields.

 

The first little problem I had was, how to show the time.  The choices I had were text single response, this would involve the user typing in the time, I didn’t like this option because it wasn’t easy for the user and had the potential for them to mistype.

The other option was to create an optionset with an hour value for each hour.  e.g. 01:00, 02:00 etc.  In then end I chose this option.

The user also wanted the ability to not select a time and this would mean they wanted to cancel the whole days appointments.

So I created the the optionSet with a default value of – Full Day and then 01:00 label would have the value of 1, 23:00 would have the value of 23.

 

dialog example

SET THE CORRECT DATA TYPE

One mistake I made at this point was to incorrectly set the Data type to text.  This is a real schoolboy error because once you set this you can’t change it.  So I had set it to text gone through adding all 24 hours and then realizing and had to do it all again, very frustrating.

What is also very frustrating is the fact you can use an optionSet created in CRM, you have to copy the values again.  This means there isn’t any schronisation between the OptionSet in your dialog and entity.  It also means you may have to create the values numerous times in a dialog because you can’t reuse it in a dialog.

In this example I had to create the same OptionSet for start date and end date.  Tedious indeed.

dialog example 1

 

The cancellation reason was the same kind of thing, I had to copy an OptionSet inside CRM and recreate it and give the OptionSet values the same as the values in the CRM OptionSet field, this way I could pass the value into the Custom Workflow and then it could use the value to set the OptionSet.

 

Warning Popup Message

When I did a demo of the functionality to the client, they said they would like a warning to pop up, if the dates specified were within 3 days.  The reason for this is if you cancel appointments with 3 days of today, it’s difficult to reorganize these so users should be certain they want to cancel these appointments.

Sometimes when someone asks you about how to achieve some functionality in CRM, you can be momentary stumped and can’t see how to do it and this was one of those moments.

I couldn’t see anyway to pop up a warning message.

It was only later that I was talking through the problem with the team that the obvious answer came to light.

Dialog’s are made up of pages and on each page you have a one or more prompt and responses.

So if I wanted a warning message all I needed to do was to create a new page, show the information the user had entered earlier in the dialog and ask them to confirm if they wanted to proceed with the changes using an OptionSet with Yes/No.

 

What I did was to check if the start date was greater than three days, if so put a confirmation page but if the start date was less than three days I would add the words warning.

dialog example 2

 

Sensible variable names

This is the same for workflows but when you are adding conditions or adding steps/prompt and responses make sure you use easily understood variable names because later you will need to use these fields to update an entity/pass to a custom workflow so you need to be able to easily understand what each field is.

Here is the Custom Workflow being called from within the dialog

dialog example 3

 

Below you can see the main code for the Custom Workflow, you can match it up with the screen shot above.  The actual code is in this class commonClientAppointment class

 


public sealed class CwaBulkAppointmentStatusChange : CodeActivity
{

/// <summary>
/// Gets or sets Min Wait Time
/// </summary>
[Input("Start Date")]
[RequiredArgument]
public InArgument<DateTime> StartDate { get; set; }

/// <summary>
/// Gets or sets Max Wait Time
/// </summary>
[Input("End Date")]
[RequiredArgument]
public InArgument<DateTime> EndDate { get; set; }

/// <summary>
/// Gets or sets Max Wait Time
/// </summary>
[Input("Start Time")]
[RequiredArgument]
public InArgument<int> StartTime { get; set; }

/// <summary>
/// Gets or sets Max Wait Time
/// </summary>
[Input("EndTime")]
[RequiredArgument]
public InArgument<int> EndTime { get; set; }

/// <summary>
/// Gets or sets Max Wait Time
/// </summary>
[Input("Cancellation Reason")]
[RequiredArgument]
public InArgument<int> CancellationReason { get; set; }

/// <summary>
/// Gets or sets Task Reference
/// </summary>
[Input("Contact")]
[ReferenceTarget("contact")]
public InArgument<EntityReference> Contact { get; set; }

/// <summary>
/// Executes the workflow activity.
/// </summary>
/// <param name="executionContext">The execution context.</param>
protected override void Execute(CodeActivityContext executionContext)
{
// Create the tracing service
ITracingService tracingService = executionContext.GetExtension<ITracingService>();

if (tracingService == null)
{
throw new InvalidPluginExecutionException("Failed to retrieve tracing service.");
}

tracingService.Trace("Entered CwaBulkAppointmentStatusChange.Execute(), Activity Instance Id: {0}, Workflow Instance Id: {1}",
executionContext.ActivityInstanceId,
executionContext.WorkflowInstanceId);

// Create the context
IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();

if (context == null)
{
throw new InvalidPluginExecutionException("Failed to retrieve workflow context.");
}

tracingService.Trace("CwaBulkAppointmentStatusChange.Execute(), Correlation Id: {0}, Initiating User: {1}",
context.CorrelationId,
context.InitiatingUserId);

IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

try
{

DateTime startDate = this.StartDate.Get(executionContext).ToLocalTime();
DateTime endDate = this.EndDate.Get(executionContext).ToLocalTime();
int startTime = this.StartTime.Get(executionContext);
int endTime = this.EndTime.Get(executionContext);
int cancellationReason = this.CancellationReason.Get(executionContext);
EntityReference contactRef = this.Contact.Get(executionContext);

CommonClientAppointment commonClientAppointment = new CommonClientAppointment();
commonClientAppointment.CancelHPAppointments(service, contactRef, startDate, endDate, startTime, endTime, cancellationReason);

}
catch (FaultException<OrganizationServiceFault> e)
{
tracingService.Trace("Exception: {0}", e.ToString());
}

tracingService.Trace("Exiting CwaBulkAppointmentStatusChange.Execute(), Correlation Id: {0}", context.CorrelationId);
}
}

 

Other interesting bits of code, below I set the start date to add the hours selected in the start time, unless it’s value is zero (which means whole day), which I then use the default time 00:00 and for enddate I give the value of 23:59 (e.g. the whole day)


if (startTime > 0)
{
startDate = startDate.Date;
startDate = startDate.AddHours(startTime);
}
else
{
startDate = startDate.Date;
}

if (endTime > 0)
{
endDate = endDate.Date;
endDate = endDate.AddHours(endTime);
}
else
{
endDate = endDate.Date;
endDate = endDate.AddHours(23).AddMinutes(59);
}

 

The other tricky bit of code was time specified code.  To recap if a time was specified then the appointments between the time should be cancelled on every day specified in the date criteria.  To do this I calculated the difference in days and then looped around that many times and added a day each time I went round  the loop.

e.g.

start date 01/01/2014

end date 07/01/2014

start time 07:00

end time 12:00

 

This would cancel all morning appointments for all the days (01, 02, 03, 04, 05 , 06, 07)

I had two options, I could either create one query with multiple date conditions or I could create one query and then repeatedly call this with the start and end date changed.

I couldn’t quite invisage doing one query so I called the query once for each day in the date range.

List<Entity> bookedAppointments = new List<Entity>();
if (startTime == 0 || endTime == 0)
{
//full days
bookedAppointments = CancelAppointmentsRetrieve(service, hpEntityRef, startDate, endDate, statusCode);
}
else
{
//time specified
int days = calculateDays(startDate, endDate);
int counter = 0;
DateTime loopEndDate = startDate.Date.AddHours(endDate.Hour);
while (counter <= days)
{
bookedAppointments.AddRange(CancelAppointmentsRetrieve(service, hpEntityRef, startDate, loopEndDate, statusCode));
startDate = startDate.AddDays(1);
loopEndDate = loopEndDate.AddDays(1);
counter++;
}
}

if (bookedAppointments != null && bookedAppointments.Count > 0)
{
this.UpdateBookedAppointments(service, bookedAppointments, cancelReasonInt);
}

&nbsp;
<pre>

 

 

 

CRM 2013 – Simple Dialog with a CRM Query

I have recently done some dialog work and I thought I would note down a dialog example whilst I could remember it.

You can watch the video below, where I go through the steps of creating the Dialog shown in this blog

If you thought workflows are quite quirky then dialog’s are like that except ten times more quirky and  in some ways they are so unlike other things in CRM, in terms of how they work that you will be left scratching your head as to what you should be doing.

Hopefully this blog post will help you get to grips with dialog’s.

The first thing you need to understand is all the definititions

The CRM 2011 wiki is a good place to start

http://social.technet.microsoft.com/wiki/contents/articles/13136.dynamics-crm-2011-dialogs.aspx

This is also a good blog post about dialogs

http://msdynamicscrmblog.wordpress.com/2013/12/02/dialogs-in-dynamics-crm-2013/

 

I will simply things in this blog because most of it you will be able to understand if you done some workflows (and everyone has done some workflows) so it’s really the dialog specific stuff we need to focus on here.

Page

A page is a page in the dialog and in that page you can have lot of prompt and responces

Prompt and response

Prompt and response is where you present the user a prompt/question and you can decide how they respond e.g.

  • Response Type – can be of the following data types:
    • None
    • Single Line – Text, Integer, or Float
    • Option Set (radio buttons) – Text, Integer, or Float
    • Options Set (picklist) – Text, Integer, or Float
    • Options Set (picklist) – Text, Integer, or Float
    • Date and Time
    • Date Only
    • Lookup – Can reference any entity type and related their related lookups

 

You can have multiple prompt and responses on a page.

You can also do the all the workflow stuff like Check condition, update record, start child workflow etc.  below is a picture of what you can do, I have highlighted the differences between workflows

simple dialog

 

One thing which is different in Dialog’s is Query CRM Data and it is quite an unusual piece of functionality.  In this simple dialog I will create a dialog which updates case records associated with an account record.

Which brings me onto another difference between workflows and dialog’s.  Dialog’s can only be triggered on one record, if you select more than one record the dialog button is hidden.  Unlike workflows which you can run on multiple selected records.

The dialog in my example will run on the account entity

QueryCRM which returns  a list of cases with the account reference equal to the account record where the dialog was triggered.

I will prompt and response

OptionSet – with the values for case origin optionset on the case

Text – capture text for the description field on the case

below you can see all the choices

simple dialog 5

The screen shot below shows the CRM query.  Notice you have to select an account in the query and then go to the modify query variables, select the account and copy over the variable for account.

simple dialog 1

Below is a screen shot of the prompt and response for the Case Origin.  You have to recreate the labels and the values in the dialog choices.

Makes sure you select the data type as integer so you can use this value to change the OptionSet

simple dialog 2

below is the dialog showing using the values collect from the Query CRM. You put the records(select cases) in the prompt and then you can show the query records in an optionset which the user can select one a case associated with the account from.

simple dialog 3

Finally I use the selected case and update the origin and description fields with responses collected earlier.

simple dialog 4

So there you go there is a simple CRM 2013 plugin using some of the core dialog functionality.

Dialog’s offer a very useful tool in CRM and they work pretty well but they take some getting use to and there are definitely a few tricks you have to learn.

 

CRM 2011 – Using Dialogs and Dialog gotchas

I read a good blog entry by Gareth Tucker about Dialog gotchas.  Dialogs are a fantastic addition to CRM 2011 and a really powerful way to interact with the user, get values and respond.

There is a couple of quirks with Dialogs

Dialogs – You can’t save dates or bits

I have written a blog post – Dialogs can’t store dates, which basically tells you can’t stores Dates, bits or lookups.  I do love dialogs and they are a great improvement it just seems the functionality needs a bit of polishing.

if you want to learn about CRM 2011 – dialogs, here are some links

Video – how to create dialogs

Dialogs – using variables

there is also a couple of good dialog entries here Dialogs Part 1 and Dialogs Part 2

Gareth has also written a good blog entry on Dialogs here

anyway here are the gotchas from Gareth’s blog entry

  1. If your Dialog has branching logic make sure you don’t use the Responses from those branches in any later actions after the branching as those Response values will not be available in those scenarios when the user branches the other way, and CRM doesn’t like that.   To get around this make use of Variables within your Dialog.  Initialise a Variable at the start of your Dialog, update it within your branch and then you can happily refer to the Variable later in the script.
  2. Beware of placing actions such as creating records and sending emails in amongst Pages of your Dialog, they’re better placed at the end of your script firing only after the user has clicked Finish in the Dialog.  Reason for this is the Dialog UI happily allows users to navigate backwards and forwards within the Dialog.  If you have a record creating firing between pages 4 and 5 of your script that record creation will happen not only the first time the user progresses to page 5 but if they hit previous, go back to page 4 and then progress on to page 5 again then yeap you guessed it you will get another record created

CRM 2011 – The difference between a plugin and a workflow

I was asked recently the difference between a plugin and a workflow and when it was best to use either.  At the time I was asked my mind went blank and I wasn’t sure.  In my mind they are both similar, so I set out to find out what the difference was.  The main difference I could think of was a workflow is asynchronous and it can fire off child workflows.

there was a good article about workflows and plugins for CRM 4 which you can read here

but then Gonzalo Ruiz has recently updated this and added in some dialog information as well, this is one of many great blog entries he has written recently

 

CRM 2011 – Dialogs can’t store Dates!

So we writing a dialog this week in CRM 2011, fantastic stuff, it has some great features allow you to show pick lists of options and getting the user to select one.

but it also has some major weaknesses like the fact you can’t store dates in Dialog, you also can’t store

Bit, Date, Lookups

This seems a bit of an oversight, not to mention you can’t use custom workflow on CRM 2011 online

So to get round this we have stored the dates as text and then convert them into dates.  So I need some code to convert Strings into Dates in my plugin and here it is.

                    newPlac.hosk_startdatetext = "20/04/2011";
                    newPlac.hosk_enddatetext = "21/04/2011";
                    DateTime startDate  = Convert.ToDateTime(newPlac.hosk_startdatetext);
                    DateTime endDate = Convert.ToDateTime(newPlac.hosk_enddatetext);

The import part is using the Convert.ToDateTime();  This is overloaded so you can specify the format if you want.