Posts

Word Cloud for Salesforce Feedback Management by Bharadwaj Kopparthi, Chocks Kandasamy, Navteshwara Kaur & Nimesh Gupta

From: Shantinath Patil: Review Your Resource

In Spring 22, the Salesforce scheduler has given a new feature: enabling rendering HTML tags in Service Resource cards. This new feature has opened up many possibilities to show additional information about the resource.

This help guide lets you add fields to the Service Resource cards: https://help.salesforce.com/s/articleView?id=sf.ls_change_the_fields_that_appear_on_the_service_resource_cards.htm&type=5.

Peer reviews and ratings are common decision making guides for customers today to help them pick among

Imagine you were to add the capabilities of a feedback management software (eg: Salesforce Feedback management) to Salesforce Scheduler, you could ask your customers to provide ratings for their appointments and then use those ratings to guide future customers.

With Feedback Management you can not only use survey invitation rules to distribute surveys when an appointment is closed but also use the data mapper feature to easily map the rating from the survey to any object in Salesforce, in this case to the Service Appointment object.

Refer to this link for more details on the datamapper and survey invitation rules

Once you have captured the rating data for your resources, there are several possibilities

  • Help the consumer decide between resources
  • Help Territory Mgr evaluate resources & branch
  • Give preferential treatment to premium customers by only showing them higher rated resources
  • Use Salesforce Einstein’s Machine Learning capabilities to predict who would be the best resource for this prospect based on past ratings giving by similar prospects eg: Someone from the South might prefer a resource from the south, or someone from an age group would prefer certain Resources.

For this blog, we’re going to focus on the Salesforce Scheduler changes you need to make to get the above capabilities going.

let’s take an example of adding a rating to the service resource. Please follow the below steps to show the shining rating stars on the resource card:

1. Fields on Service Resource

To show the rating, we need to create a formula field on Service Resource to render rating stars in cards. We will add this field to the compact layout to show up in the out of the box component. However, to populate value in this field, we need two more fields on Service Resource: to capture the average rating for each of the appointments he served and the number of appointments.

Field LabelField API NameData TypeComments
RatingRating__cNumber(1,0)Number field to store rating between 1-5
Review CountReview_Count__cNumber(18,0)Number field to store number of reviews this service resource have received
Star RatingStar_Rating__cFormula(Text)Formula field which will show ratings based on above 2 fields

The sample formula will turn out like this:

IMAGE(
IF(TEXT( CEILING(Rating__c) ) = '0', "/img/samples/stars_000.gif",
IF(TEXT( CEILING(Rating__c) ) = '1', "/img/samples/stars_100.gif",
IF(TEXT( CEILING(Rating__c) ) = '2', "/img/samples/stars_200.gif",
IF(TEXT( CEILING(Rating__c) ) = '3', "/img/samples/stars_300.gif",
IF(TEXT( CEILING(Rating__c) ) = '4', "/img/samples/stars_400.gif",
IF(TEXT( CEILING(Rating__c) ) = '5', "/img/samples/stars_500.gif",
"/img/samples/stars_000.gif"
)
)
)
)
)
),
'Rating Level'
) + ' ('+ TEXT( Review_Count__c ) + ' Reviews)'

2. Field on Service Appointment

We will have to create a field on Service Appointment to capture the sentiment of a customer based on how the appointment went. We can populate this value from a Survey, which will be sent out once an appointment is complete.

Field LabelField API NameData TypeComments
RatingRating__cNumber(1,0)Number field to store rating between 1-5

3. Propagate value from Service Appointment to Service Resource

Now that we have fields on Service Resource and Service Appointment, we will have to process the aggregate reviews. As shown in the below data model diagram, we can traverse through Assigned Resource and populate this value to Service Resource.

The review aggregator formula that we can use is:

 ((Current Average Rating * Total Reviews) + New Rating) / (Total Reviews+ 1)

Using this formula, we can write a trigger on Service Appointment. As soon as we get a rating from Service Appointment, we will aggregate the review and update its corresponding Service Resource. A sample trigger code is given below:

trigger UpdateSurveyRating on ServiceAppointment (after insert, after update) {

Set<Id> vSetServiceAppointment = new Set<Id>();

for(ServiceAppointment sapp : Trigger.new){
if(Trigger.isInsert && sapp.Rating__c != null){
vSetServiceAppointment.add(sapp.Id);
}else if(Trigger.isUpdate && Trigger.oldMap.get(sapp.Id).Rating__c != sapp.Rating__c){
vSetServiceAppointment.add(sapp.Id);
}
}

if(!vSetServiceAppointment.isEmpty()){

Map<Id, List<ServiceResource>> vMapServiceAppToResources = new Map<Id, List<ServiceResource>>();
List<AssignedResource> vListAssResource = [SELECT Id, ServiceResourceId, ServiceAppointmentId FROM AssignedResource WHERE ServiceAppointmentId IN: vSetServiceAppointment];

if(vListAssResource != NULL && !vListAssResource.isEmpty()){

Set<Id> vSetServiceResource = new Set<Id>();

for(AssignedResource vAssRes : vListAssResource){
vSetServiceResource.add(vAssRes.ServiceResourceId);
}

Map<Id, ServiceResource> vMapServiceResource = new Map<Id, ServiceResource>([SELECT Id, Rating__c, Review_Count__c FROM ServiceResource WHERE Id IN: vSetServiceResource]);
for(AssignedResource vAssRes : vListAssResource){
if(!vMapServiceAppToResources.keySet().isEmpty() && vMapServiceAppToResources.containsKey(vAssRes.ServiceAppointmentId)){
List<ServiceResource> vTempResources = vMapServiceAppToResources.get(vAssRes.ServiceAppointmentId);
vTempResources.add(vMapServiceResource.get(vAssRes.ServiceResourceId));
vMapServiceAppToResources.put(vAssRes.ServiceAppointmentId, vTempResources);
}else{
List<ServiceResource> vTempResources = new List<ServiceResource>();
vTempResources.add(vMapServiceResource.get(vAssRes.ServiceResourceId));
vMapServiceAppToResources.put(vAssRes.ServiceAppointmentId, vTempResources);
}
}

//((Current Average Rating * Total Reviews) + New Rating) / (Total Reviews+ 1)
Map<Id, ServiceResource> vMapServiceResourceToUpdate = new Map<Id, ServiceResource>();
for(ServiceAppointment sapp : Trigger.new){
if(vMapServiceAppToResources.containsKey(sapp.Id)){
for(ServiceResource vResource : vMapServiceAppToResources.get(sapp.Id)){
if(vMapServiceResourceToUpdate != NULL && vMapServiceResourceToUpdate.containsKey(vResource.Id)){
ServiceResource vTempResource = vMapServiceResourceToUpdate.get(vResource.Id);
vTempResource.Rating__c = (((vTempResource.Rating__c * vTempResource.Review_Count__c) + sapp.Rating__c) / vTempResource.Review_Count__c+1);
vTempResource.Review_Count__c++;
vMapServiceResourceToUpdate.put(vTempResource.Id, vTempResource);
}else{
Decimal rating = vResource.Rating__c != NULL ? vResource.Rating__c : 0;
Decimal reviews = vResource.Review_Count__c != NULL ? vResource.Review_Count__c : 0;
vResource.Rating__c = (((rating * reviews) + sapp.Rating__c) / (reviews+1));
vResource.Review_Count__c = ++reviews;
vMapServiceResourceToUpdate.put(vResource.Id, vResource);
}
}
}
}

UPDATE vMapServiceResourceToUpdate.values();
}
}
}

Note: This is just a concept illustrator built for a simple create Guest appointment use case using the out of the box flow template.

Possibilities