The error message "You can't configure a booking on this service using legacy scheduling experience" clearly indicates that the Service record you are trying to book against is configured to use the Unified Interface scheduling experience, while your code is likely attempting to use the older, legacy scheduling methods.
With the introduction of the Unified Interface, Microsoft has transitioned to a new scheduling engine and interface. The legacy methods and configurations are no longer compatible with services configured for this new experience.
Here's a breakdown of why this is happening and how to resolve it:
Understanding the Issue:
- Unified Interface Scheduling: Dynamics 365 Customer Service (and related modules) in the Unified Interface uses a modern scheduling engine with features like schedule board enhancements and optimized resource finding. Services can be configured to leverage this new experience.
- Legacy Scheduling: Older versions of Dynamics 365 used a different, "legacy" scheduling mechanism.
- Incompatibility: When a Service record is set to use the Unified Interface scheduling, attempting to book against it using the legacy
BookRequest and SearchRequest classes will result in this error.
How to Resolve It:
You need to adapt your code to use the Unified Interface scheduling APIs. This typically involves using the following:
ScheduleRequest Class: This class is part of the Unified Interface scheduling API and is used to find available time slots for resources based on the requirements of the service activity.
BookServiceRequest Class: This class is used to create the actual booking (BookableResourceBooking) based on the selected time slot and resources.
Steps to Update Your Code:
- Identify the Service Configuration: First, you need to determine how the specific Service record you are working with is configured for scheduling. In the Unified Interface, this is often managed within the Service Management area. Look for settings related to scheduling and ensure the service is not explicitly set to use a legacy mode (though the error message strongly suggests it is using the new one).
- Replace
SearchRequest with ScheduleRequest: Modify your code to use the ScheduleRequest class instead of SearchRequest to find available resources and time slots. This request will require parameters that define the service, required resources, duration, and scheduling constraints.
- Replace
BookRequest with BookServiceRequest: Once you have identified an available time slot and resources using ScheduleRequest, use the BookServiceRequest class to create the booking. This request will take parameters like the selected resource, start and end time, and the service activity.
Example (Conceptual - You'll need to adapt this to your specific requirements and field names):
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk;
using System;
public class YourSchedulingClass
{
public void ScheduleServiceActivity(IOrganizationService service, Guid serviceActivityId, Guid serviceId, DateTime desiredStartTime)
{
try
{
// 1. Retrieve the Service Activity and Service records if needed
Entity serviceActivity = service.Retrieve("serviceappointment", serviceActivityId, new Microsoft.Xrm.Sdk.Query.ColumnSet(true));
Entity serviceRecord = service.Retrieve("service", serviceId, new Microsoft.Xrm.Sdk.Query.ColumnSet(true));
// 2. Create the ScheduleRequest
ScheduleRequest scheduleRequest = new ScheduleRequest
{
ResourceId = serviceId, // Likely the Service record ID
Direction = ScheduleDirection.Forward,
StartDateTime = desiredStartTime,
EndDateTime = desiredStartTime.AddHours(serviceActivity.GetAttributeValue<double>("scheduleddurationminutes") / 60.0), // Calculate end time
Slots = new TimeCode[1] { new TimeCode { Start = desiredStartTime, End = desiredStartTime.AddHours(serviceActivity.GetAttributeValue<double>("scheduleddurationminutes") / 60.0) } },
Query = "<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>" +
"<entity name='bookableresource'>" +
"<attribute name='name' />" +
"<attribute name='bookableresourceid' />" +
"<order attribute='name' descending='false' />" +
"</entity>" +
"</fetch>", // FetchXML to retrieve available bookable resources (adjust as needed)
// Add other constraints and preferences as required
};
ScheduleResponse scheduleResponse = (ScheduleResponse)service.Execute(scheduleRequest);
if (scheduleResponse != null && scheduleResponse.TimeSlots != null && scheduleResponse.TimeSlots.Length > 0)
{
// Assuming you pick the first available slot and resource
Guid bookableResourceId = scheduleResponse.TimeSlots[0].ResourceId.Id;
DateTime bookingStartTime = scheduleResponse.TimeSlots[0].Start;
DateTime bookingEndTime = scheduleResponse.TimeSlots[0].End;
// 3. Create the BookServiceRequest
BookServiceRequest bookServiceRequest = new BookServiceRequest
{
ResourceId = bookableResourceId,
Target = new EntityReference("serviceappointment", serviceActivityId),
StartDateTime = bookingStartTime,
EndDateTime = bookingEndTime
};
BookServiceResponse bookServiceResponse = (BookServiceResponse)service.Execute(bookServiceRequest);
if (bookServiceResponse != null && bookServiceResponse.Success)
{
Console.WriteLine($"Service Activity {serviceActivityId} booked successfully for resource {bookableResourceId} at {bookingStartTime}.");
}
else
{
Console.WriteLine($"Error booking Service Activity: {bookServiceResponse?.ErrorDetails?.Message}");
}
}
else
{
Console.WriteLine("No available time slots found.");
}
}
catch (Exception ex)
{
Console.WriteLine($"Error during scheduling: {ex.Message}");
Console.WriteLine(ex.ToString());
}
}
// Example usage (replace with your actual context and IDs)
public static void ExampleSchedule(IOrganizationService service)
{
Guid serviceActivityId = new Guid("YOUR_SERVICE_ACTIVITY_ID");
Guid serviceId = new Guid("YOUR_SERVICE_ID");
DateTime desiredStartTime = DateTime.Now.AddDays(1);
YourSchedulingClass scheduler = new YourSchedulingClass();
scheduler.ScheduleServiceActivity(service, serviceActivityId, serviceId, desiredStartTime);
}
}
Key Changes and Considerations:
ScheduleRequest: Used to find available slots. You'll need to construct the Query (FetchXML) to specify which resources are considered for scheduling. This might involve filtering by roles, skills, or other criteria.
BookServiceRequest: Used to create the actual booking.
- Resource Identification: In the Unified Interface, resources are typically
BookableResource records. Your ScheduleRequest's FetchXML needs to target this entity.
- Time Slots: The
ScheduleResponse will return an array of TimeCode objects representing available time slots and the associated resources.
- Error Handling: Ensure you have robust error handling to catch potential issues during the scheduling process.
- Context: The example assumes you have the
IOrganizationService instance available. You'll need to adapt the example usage to fit within your plugin's Execute method.
- FetchXML for Resources: The provided FetchXML in
ScheduleRequest is a basic example. You'll likely need to make it more specific based on your resource requirements.
In summary, the error you are encountering indicates a mismatch between the scheduling API you are using (legacy BookRequest and SearchRequest) and the configuration of the Service record (using Unified Interface scheduling). You need to update your code to use the ScheduleRequest and BookServiceRequest classes from the Unified Interface scheduling API to interact with these services. Review the Microsoft Dynamics 365 documentation for the Unified Interface scheduling APIs for more detailed information and examples.