March 28, 2019

Update user’s calendar in Field Service schedule board

Configuring the work hours for a user is straightforward from the Dynamics 365 UI, a couple of clicks and you are done. However in the last years we saw an increase of Field Service projects, hence the necessity to automatize the creation and the update of user's works hours.
C# code to update the calendar entity has been around from CRM 2011, like this one:
Sample code to update user’s calendar programmatically (work hours) in CRM 2011

The code linked above works perfectly when you see the work hours inside the user calendar, however they don't appear inside the Field Service schedule board. How can we make sure the work hours appear everywhere?

Nearly 50 lines of code to create a work hour entry are (at least to me) a bit excessive, but this is the way Dynamics work. I tried to simplify the code by renaming the variables and adding the code necessary for the work hours to appear inside the schedule board.
// we start with the user Id
Guid userId = Guid.Empty; // instead of Guid.Empty here we should have the real user Id

// we retrieve the calendarid from the user entity
Entity user = service.Retrieve("systemuser", userId, new ColumnSet("calendarid"));
Guid userCalendarId = user.GetAttributeValue("calendarid").Id;

// we retrieve the calendar record in order to get the Business Unit and the Calendar Rules
Entity userCalendar = service.Retrieve("calendar", userCalendarId , new ColumnSet("businessunitid"));
Guid calendarBusinessUnitRef = userCalendar.GetAttributeValue("businessunitid");
EntityCollection calendarRules = userCalendar.GetAttributeValue("calendarrules");

// we create a new calendar record (inner)
Entity innerCalendar = new Entity("calendar");
innerCalendar["businessunitid"] = calendarBusinessUnitRef;

// Field Service Schedule Board: we must define the type as Inner Calendar
// https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/types-calendars
innerCalendar["type"] = new OptionSetValue(-1);

Guid innerCalendarId = service.Create(innerCalendar);

// we create a calendar rule for the whole day we want to edit
Entity dayRule = new Entity("calendarrule");
dayRule["duration"] = 1440; // 24 hours in minutes
dayRule["effort"] = 1.0;
dayRule["extentcode"] = 1;
dayRule["pattern"] = "FREQ=DAILY;COUNT=1";
dayRule["rank"] = 0;
dayRule["timezonecode"] = 110; // 110 is (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
// GetAllTimeZonesWithDisplayNameRequest can be used to retrieve all the timezones with their code
dayRule["starttime"] = new DateTime(2019, 3, 28, 0, 0, 0, DateTimeKind.Utc);
dayRule["innercalendarid"] = new EntityReference("calendar", innerCalendarId);

// Field Service Schedule Board: we must also define the calendarid reference to the user calendar
dayRule["calendarid"] = new EntityReference("calendar", userCalendarId);

// we attach it to the Calendar Rules of the user
calendarRules.Entities.Add(dayRule);

// we update the user calendar to refresh the calendar rules collection
Entity updateUserCalendar = new Entity("calendar", userCalendarId);
updateUserCalendar["calendarrules"] = calendarRules;
service.Update(updateUserCalendar);

// we define the calendar rule containing our work hour 
Entity exactCalendarRule = new Entity("calendarrule");
exactCalendarRule["duration"] = 120; // 2 hours in minutes
exactCalendarRule["effort"] = 1.0;
exactCalendarRule["issimple"] = true;
exactCalendarRule["offset"] = 480; // 8 hours in minutes from start time (12:00)
exactCalendarRule["rank"] = 0;
exactCalendarRule["subcode"] = 1;
exactCalendarRule["timecode"] = 0;
exactCalendarRule["timezonecode"] = 110; // same timezone as the day rule
exactCalendarRule["calendarid"] = new EntityReference("calendar", innerCalendarId);

// we add the calendar rule to a collection
EntityCollection innerCalendarRules = new EntityCollection();
innerCalendarRules.EntityName = "calendarrule";
innerCalendarRules.Entities.Add(exactCalendarRule);

// we update the inner calendar with the new calendar rules 
innerCalendar["calendarrules"] = innerCalendarRules;
innerCalendar["calendarid"] = innerCalendarId;
service.Update(innerCalendar);

In the end to changes were necessary to make the work hour visible inside the Field Service schedule board:
  1. We must define the type for the Inner Calendar
  2. We must reference the user calendar inside the calendar rule the the whole day
I didn't discover this by myself but with the help of Microsoft support, hope it helps.

January 14, 2019

getText API behavior changed

Some days ago I was upgrading some JavaScript files to v9 and I noticed one of the scripts was not working correctly.
The specific code was using the getText function in order to retrieve the label of an optionset field. The getText function used to return an empty string in Dynamics instances prior to CRM 2016, but in recent versions it returns null. If you need to handle the label in your code (like showing some alerts) the check should be like this one:
function checkOptionsetLabel(context, fieldName) {
    var selectedLabel = context.getAttribute(fieldName).getText();
    if (selectedLabel != null) {
        // ...
    }
}
Also the official documentation has been updated to highlight the return value. Hope it helps!

December 31, 2018

Dynamics Weekly and recap of (my) 2018

If you were hoping to read (after long time) a technical post from me, I am sorry but you need to wait a bit longer :)
In this post I will write about Dynamics Weekly (first part) and what I have been up to during 2018 (second part), let's start.

Dynamics Weekly is my newsletter regarding Dynamics 365 CE, I started it in the end of 2017 and it's going well.

A chart of the subscribers: (click to zoom)

This chart shows 2 things:
  1. There is a steady increase of the subscribers, that's nice
  2. I am terrible at promoting the newsletter, because except the initial grow (maybe due to my spamming on Twitter and LinkedIn) the final count is relatively low
I want to tell how Dynamics Weekly started. Back in December 2017 I realized that due to my commitments (both work and personal) I was not able to keep track of all the news, Dynamics is my work but I also like it and it's pity if I miss the cool stuff.
I already knew that the 2018 would have been the same, so I needed a way to force myself to check the Dynamics world. A weekly newsletter is a good way to summarize the content published during the last days, also having the email in my inbox allows me to search for specific posts that I vaguely remember just using few keywords.

Most of the time I am able to collect the newsletter material during the week, sometimes I do the Sunday evening before the send. But Keep Dynamics Weekly running is useful to me and to the subscribers, in the last year I received many messages of appreciation, thanks to all of you.
Of course Dynamics Weekly would not exist without all the contributors in the Dynamics communities, I am honored to know some of them and the time and energy they spend creating all kind of content is way more important than mine spent on preparing the newsletter.

And now the second (brief) part of this post. How was my 2018? to be honest not great, it really drained me of energy and the final reward was very small. But I met new friends, I learned new things (not related to Dynamics) and I am positive 2019 will be a better year.

PS: 19 January I will join the "Dynamics Power! 365 Saturday London" event, see you there.

Thanks!

August 11, 2018

Display a Two Options field as checkbox inside a Quick View Form

The other day I was working on a project involving a Quick View Form, nothing complicated but in the end it required some additional steps to achieve the desired result.
The purpose of this Quick View Form (for the Account entity) was to show a single Two Options field, so the users don't need to open the related account record to see the value of this boolean field.
As usual I created the Quick View Form, added the Two Options Field, save & publish, added the Quick View Form inside the other entity, save & publish. All was working except the Two Options Field was displaying as a label showing Yes or No:



As I need to show this field as a checkbox, first thing I thought was: "no big deal, I back to the form editor and I change the formatting to show a checkbox", the only problem is that the "Formatting" tab inside the field properties is missing when you work with a Quick View Form:



So it is not possible to set the Control Formatting style to display the field as a checkbox, as you can do inside a standard or a Quick Create Form:



A workaround is to manually edit the solution XML and change the classid attribute of the control to a specific value.

Beware: you should do this kind of editing only if you know what you are doing, I don't encourage to go and edit files without having a proper knowledge of the XML structure.

First step I did is to create a new solution containing just the Quick View Form I needed to edit, this is possible with the "Select Entity Assets" wizard of the latest versions of Dynamics, if you are on an older version you need to add the entire entity (with all the forms, views and fields) to the new solution.



After I exported the solution as Unmanaged, I extracted the zip file to a folder and I edited the file customizations.xml. In order to find the right place to edit I searched for the logical name of the field (in my case marketingonly) and I was in front of the definition:
<cell id="{32660749-eb65-6c8d-208c-664929db91db}" showlabel="true" locklevel="0">
  <labels>
    <label description="Marketing Only" languagecode="1033" />
  </labels>
  <control id="marketingonly" classid="{67FAC785-CD58-4F9F-ABB3-4B7DDC6ED5ED}" datafieldname="marketingonly" disabled="false" uniqueid="{b751c953-ac42-7723-a3c5-d4c7b0514c0b}" />
</cell>
As I mentioned before the attribute to update is classid, so I changed the guid value to {B0C6723A-8503-4FD7-BB28-C8A06AC933C2}, if someone is curious where this specific value comes from, it is listed inside the FormXml definition as the value for CheckBoxControl, or you can export another form with a checkbox and you will find the same guid value.

Done with the edit I saved the file, zipped the solution files, imported and published, and finally the Quick View Form now shows a checkbox:



Hope it helps!

July 15, 2018

Say No to local Option sets (but pay attention in PowerApps)

The use of global option sets in Dynamics is normally considered a best practice, the obvious advantage is the ability to reuse the same list of options in multiple fields inside the same entity or a different one.
Dynamics still allows the creation of local option sets but from version v9 there is another difference between Local and Global option sets: the External Value property:

This property is available only on Global option sets, when you create a local option this new property is missing:

External Value is intended for Virtual Entities, I understand it's not an everyday situation to deal with it, but this gives you another reason to avoid local option sets.

Today we live in the world of CDS and PowerApps, but the choice between local and global option sets is also inside the Canvas mode. If before the creation of fields was handled generally by System Administrators (in what we call today model-driven apps), today a larger set of user can face this dilemma.
Microsoft published a detailed page regarding option sets inside PowerApps here:
Create an Option set
So make your users aware of the "Option sets" inside the navigation pane:
Although I agree with the warning written by Microsoft

"Local option sets can only be used by the entity and field they are created against, and cannot be reused on other entities. This approach is only recommended for advanced users that a specific need for a local option set."

teach your users that the options inside a global option set will be available in all the fields using that option set, so if you add or remove options this will affect also other fields created by different users based on the existing option set.

January 27, 2018

365 Saturday London: recap of the Community Event

As I anticipated in my previous post, this weekend I attended the 365 Saturday event in London (http://365saturday.com/dynamics/london-jan2018/), if I need to describe the event in one word? EPIC.

This 365 Saturday was a 2 days event, the first part on Friday afternoon with the Hackathon and the second part on Saturday with many sessions (there were 5 tracks!) from early morning until 6pm, practically a full day of Dynamics 365 content.

The Friday Hackahton was divided in two tracks, the first one regarding Field Service by @BenVollmer from Microsoft the second track was focused on various aspects of Dynamics 365: Machine Learning, Microsoft Portals, Xamarin and XrmToolBox, the must-have tool for Dynamics professionals. Personally I followed the Field Service part of the Hackathon and during the breaks I snooped into the other track :)

The Hackthon was very interesting but Saturday has been off the charts. The day started with the keynote of James Phillips, Microsoft Vice President in charge of the Dynamics products and he dropped the big news of the day: Microsoft decided to revert the deprecation of the the Outlook Client, I will not go into the details as I am sure in the next days there will be detailed blog posts regarding this important announcement.

As I don't have the gift of ubiquity (yet) I was able to attend only few sessions, I started with the one by Ramón Tébar Bueno and Baris Kanlica regarding Dynamics 365 v9 I did a speech at CRM Saturday Milan back in November about the same argument, but this session confirmed me one thing: Dynamics 365 v9 is full of new features and is difficult to concentrate all of them inside 1 hour.

The second session I followed was the "GDPR Considerations" by Mohamed Mostafa GDPR is a delicate argument and the deadline (25 May 2018) is near the corner, we (Dynamics professionals) should focus more on this topic and Mohamed session was very helpful to understand some of the key points of the regulation.

The next session was "Resource Scheduling Optimization" by Ben Vollmer, a different session was scheduled for this slot but the speaker was not able to attend, so Ben kindly step in and delivered this unexpected session regarding Field Service RSO. Resource Scheduling Optimization is a very interesting tool and I'm glad that I learned something about it.

The last session was about PowerApps, Flow and PowerBI, delivered by Darshan Desai and Rory Neary The first part Darshan talked about PowerApps and Flow and the second part was delivered by Rory where he presented an interactive PowerBI dashboard embedding a PowerApps app designed for James Bond (the event was in UK, logical choice), the session was the right mix between technical content and entertainment.

Last but not least, the 365 Saturday supports women in tech, Janet Robb who works for Microsoft and helped in the organization of the event is our advocate for this important cause: I'm very happy that I joined the first 365 Saturday of 2018, I met old friends, made new ones and meanwhile I learned something new about Dynamics 365, it's amazing. Last thing: don't forget to check their website (http://365saturday.com/) for the upcoming events!

January 22, 2018

365 Saturday in London and what I have been up to

This weekend (26 and 27 January) I will be in London to attend the 365 Saturday event (http://365saturday.com/dynamics/london-jan2018/).
I'm sure that 365 Saturday will be a big event, not only because is the first one with the new brand (it was previously known as CRM Saturday) but the speaker lineup is impressive: in addition to several MVPs that will go deep-dive into various subjects, James Phillips (Microsoft Corporate Vice President) will be the keynote speaker and Ben Vollmer (Microsoft Global Field Service Lead) will host a workshop regarding Field Service.

Registrations are now closed for the London event, but check their website (365saturday.com/) to find the next events, like the one in Amsterdam next month or the one in Dallas in March (first time in the USA).

And now just a quick update on what I did in the last months regarding Dynamics CRM/365:
  • 25 November 2017 I was one of the speakers for CRM Saturday in Milan, big thanks to Stefano Tempesta for organizing the event. I did a session on the new and deprecated features of Dynamics 365 v9, I had a great discussion with the participants and soon it's UPGRADE TIME!
  • Still in November I was invited to the CRM Audio podcast (episode here) for a little chat regarding Dynamics. CRM Audio hosts several podcasts like the one about PowerBI or the "Implement This" series, check it out.
  • Dependent OptionSet Generator: After the V9 release I decided to update my solution for dependent optionsets (download here). The big news is the support for the Multi Select OptionSets. The demo has also been updated for this release.
  • Dynamics Weekly (www.dynamicsweekly.com): Back in December I decided to start a newsletter regarding Dynamics, the idea is to organize fresh content (articles, tools, videos, podcasts released in the previous week) delivered directly to your inbox. This morning I sent the 8th issue and there are nearly 200 subscribers.
Posted on Monday, January 22, 2018 | Categories: