If you have lots of users which need their work hours added into CRM, it can take a long time to manually set up each user through the user interface.
Below is the code to update user’s work hours in bulk for a regular 9am-5pm schedule and will also reflect on the Universal Resource Scheduling board.
using Microsoft.Xrm.Sdk; using Microsoft.Xrm.Sdk.Client; using Microsoft.Crm.Sdk.Messages; using System.Net; using System.ServiceModel.Description; using System; using Microsoft.Xrm.Sdk.Query; using System.Collections.Generic; namespace BulkCreateWorkHours { class Program { private static Guid Systemusers; private static string Names; static void Main(string[] args) { IOrganizationService organizationService = null; try { //Login details ClientCredentials clientCredentials = new ClientCredentials(); clientCredentials.UserName.UserName = "email"; clientCredentials.UserName.Password = "password"; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; //CRM Organisation URL details organizationService = (IOrganizationService)new OrganizationServiceProxy(new Uri("https://XXXXXXX.api.XX.dynamics.com/XRMServices/2011/Organization.svc"), null, clientCredentials, null); if (organizationService != null) { Guid userid = ((WhoAmIResponse)organizationService.Execute(new WhoAmIRequest())).UserId; Console.WriteLine("Connection Established Successfully..."); //Fetches all Users which have a Bookable Resource string fetchxml = "<?xml version='1.0'?>" + "<fetch distinct='true' mapping='logical' output-format='xml-platform' version='1.0'>" + "<entity name='systemuser'>" + "<attribute name='systemuserid'/>" + "<attribute name='firstname'/>" + "<attribute name='lastname'/>" + "<order descending='false' attribute='firstname'/>" + "<link-entity name='bookableresource' alias='ac' link-type='inner' to='systemuserid' from='userid'/>" + "</entity>" + "</fetch>"; EntityCollection result = organizationService.RetrieveMultiple(new FetchExpression(fetchxml)); Console.WriteLine("There are {0} entities found", result.Entities.Count); foreach (var c in result.Entities) { Systemusers = ((Guid)c.Attributes["systemuserid"]); Names = ((string)c.Attributes["firstname"]) + " " + ((string)c.Attributes["lastname"]); //Clears original Calander Rules for all of the Users retrieved from the fetch ClearCalenderRules(organizationService, Systemusers); //Add new Calander Rules for all of the Users retrieved from the fetch AddCalenderRules(organizationService, Systemusers); } Console.WriteLine("COMPLETE"); } else { Console.WriteLine("Failed to Established Connection!!!"); } } catch (Exception ex) { Console.WriteLine("Exception caught - " + ex.Message); } Console.ReadKey(); } public static void AddCalenderRules(IOrganizationService organizationService, Guid userid) { if (userid != Guid.Empty) { Entity systemUserEntity = organizationService.Retrieve("systemuser", Systemusers, new ColumnSet(new String[] { "calendarid" })); Entity userCalendarEntity = organizationService.Retrieve("calendar", ((Microsoft.Xrm.Sdk.EntityReference)(systemUserEntity.Attributes["calendarid"])).Id, new ColumnSet(true)); EntityCollection calendarRules = (EntityCollection)userCalendarEntity.Attributes["calendarrules"]; Entity newInnerCalendar = new Entity("calendar"); newInnerCalendar.Attributes["businessunitid"] = new EntityReference("businessunit", ((Microsoft.Xrm.Sdk.EntityReference)(userCalendarEntity["businessunitid"])).Id); Guid innerCalendarId = organizationService.Create(newInnerCalendar); //Create a new calendar rule and assign the inner calendar id to it Entity calendarRule = new Entity("calendarrule"); calendarRule.Attributes["duration"] = 1440; calendarRule.Attributes["extentcode"] = 1; //Create a pattern of Mon-Fri calendarRule.Attributes["pattern"] = "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR"; calendarRule.Attributes["rank"] = 0; //85 = UK Time Code calendarRule.Attributes["timezonecode"] = 85; calendarRule.Attributes["innercalendarid"] = new EntityReference("calendar", innerCalendarId); //Starting at 12:00 on 1 January 2018 calendarRule.Attributes["starttime"] = new DateTime(2018, 01, 01, 0, 0, 0, DateTimeKind.Utc); calendarRules.Entities.Add(calendarRule); //Assign all the calendar rule back to the user calendar userCalendarEntity.Attributes["calendarrules"] = calendarRules; //Please refer to here for Calander Types https://msdn.microsoft.com/en-us/library/dn689038.aspx userCalendarEntity.Attributes["type"] = new OptionSetValue(-1); organizationService.Update(userCalendarEntity); //Creates a new Calendar Rule Entity calendarRule1 = new Entity("calendarrule"); //Duration of 9 hours (540 mins) calendarRule1.Attributes["duration"] = 540; calendarRule1.Attributes["effort"] = 1.0; calendarRule1.Attributes["issimple"] = true; //Offset of 8 hours (480 mins) - Start Time is 8am calendarRule1.Attributes["offset"] = 480; calendarRule1.Attributes["rank"] = 0; calendarRule1.Attributes["subcode"] = 1; calendarRule1.Attributes["timecode"] = 0; calendarRule1.Attributes["timezonecode"] = -1; calendarRule1.Attributes["calendarid"] = new EntityReference("calendar", innerCalendarId); EntityCollection innerCalendarRules = new EntityCollection(); innerCalendarRules.EntityName = "calendarrule"; innerCalendarRules.Entities.Add(calendarRule1); newInnerCalendar.Attributes["calendarrules"] = innerCalendarRules; newInnerCalendar.Attributes["calendarid"] = innerCalendarId; organizationService.Update(newInnerCalendar); Console.WriteLine("Work Hours Added to " + Names); } } public static void ClearCalenderRules(IOrganizationService organizationService, Guid userId) { if (userId != null) { //Retrieves all CalanderId's for all the users string fetchxml = "<?xml version='1.0'?>" + "<fetch distinct='true' mapping='logical' output-format='xml-platform' version='1.0'>" + "<entity name='calendar' >" + " <attribute name='calendarid' />" + " <filter type='and' >" + " <condition attribute='primaryuserid' operator='eq' value='" + userId + "' />" + " </filter>" + " </entity>" + "</fetch>"; EntityCollection result = organizationService.RetrieveMultiple(new FetchExpression(fetchxml)); Console.WriteLine("There are {0} entities found", result.Entities.Count); foreach (var c in result.Entities) { Entity Calendar = organizationService.Retrieve("calendar", ((Guid)c.Attributes["calendarid"]), new ColumnSet(true)); EntityCollection calendarRules = (EntityCollection)Calendar.Attributes["calendarrules"]; int num = 0; List<int> list = new List<int>(); foreach (Entity current in calendarRules.Entities) { list.Add(num); num++; } list.Sort(); list.Reverse(); for (int i = 0; i < list.Count; i++) { //Remove all Calander Rules from Collection calendarRules.Entities.Remove(calendarRules.Entities[list[i]]); } //Assign Calander Rules to empty Entity Collection Calendar.Attributes["calendarrules"] = calendarRules; organizationService.Update(Calendar); Console.WriteLine("Work Hours Deleted for " + Names); } } } } }
This code works in 2 steps:
- I created a Fetch to retrieve all users which have a Bookable Resource.
- I run a for each loop through each user and pass that UserId into two methods:
ClearCalenderRules(organizationService, Systemusers);
This method clears the current Calendar of the users.
AddCalenderRules(organizationService, Systemusers);
This method adds the Calendar rule specified for the users.
Important parts of the code that needs expanding:
userCalendarEntity.Attributes["type"] = new OptionSetValue(-1);
You need to specify the ‘type’ attribute as -1 because this will then reflect on the Schedule Board. Here is a link for more information https://msdn.microsoft.com/en-us/library/dn689038.aspx
calendarRule.Attributes["pattern"] = "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR";
This pattern string specifies a schedule frequency for Monday to Friday. You can see more examples of different patterns here https://www.syncfusion.com/kb/3719/what-is-recurrencerule-in-the-schedule-control
Hopefully this post helps 🙂
Is it feasible to add work order assigned to resources in Work Hours Calendar ?
Hi Sumanta,
Im not sure what you mean, can you give a detailed example?