Recommend Tasks Using Apex
Create an Apex class to select a list of visits or visit recommendations that Einstein must provide task recommendations for.
Required Editions
| Available in Lightning Experience in Professional, Unlimited, and Enterprise Editions that have Consumer Goods Cloud enabled. |
Important To use an Apex action in a flow, ask your developer to
annotate the appropriate method with @InvocableMethod.
Here's what an Apex class for filtering visit or visit recommendation to get task recommendations look like:
global class SampleTaskRecommendation {
global class Recommendation {
@InvocableVariable
global List<String> ParentTaskIDs = new List<String>();
@InvocableVariable
global List<String> RecommendedTargetIDs = new List<String>();
@InvocableVariable
global List<String> TemplateRecordIDs = new List<String>();
@InvocableVariable
global List<String> TaskRecommendationReasons = new List<String>();
}
@InvocableMethod(label='Task recommendation' description='Returns a list of task recommendations')
global static List<Recommendation> getTaskRecommendations(List<List<String>> TargetIDs) {
List<String> ParentTaskIDs = new List<String>();
List<String> RecommendedTargetIDs = new List<String>();
List<String> TemplateRecordIDs = new List<String>();
List<String> TaskRecommendationReasons = new List<String>();
List<String> inputTargetIds = TargetIDs.get(0);
for(String targetID : inputTargetIds) {
Visit[] visits = null;
AiVisitRecommendation[] aiVisitRecommendations = [SELECT VisitSite.Id FROM AiVisitRecommendation WHERE id = :targetID];
if(aiVisitRecommendations != null && aiVisitRecommendations.size() > 0) {
AiVisitRecommendation aiVisitRecommendation = aiVisitRecommendations[0];
visits = [SELECT Id, PlaceId FROM Visit WHERE Placeid = :aiVisitRecommendation.VisitSite.Id AND Status = 'Completed' ORDER BY ActualVisitEndTime DESC LIMIT 1];
} else {
Visit[] visitsForTargetId = [SELECT Id, PlaceId FROM Visit WHERE Id = :targetID LIMIT 1];
Visit visitForTargetId = visitsForTargetId[0];
visits = [SELECT Id, PlaceId FROM Visit WHERE Id = :targetID AND PlaceId = :visitForTargetId.PlaceId LIMIT 1];
}
if(visits != null && visits.size() > 0) {
Visit visit = visits[0];
populateTaskRecommendationsForMoreThan50PercNonCompliantKPIs(targetID, ParentTaskIDs, RecommendedTargetIDs,
TemplateRecordIDs, TaskRecommendationReasons, visit);
populateTaskRecommendationForSurvey(targetID, ParentTaskIDs, RecommendedTargetIDs,
TemplateRecordIDs, TaskRecommendationReasons, visit);
populateOrderTaskRecommendationForOOSKpi(targetID, ParentTaskIDs, RecommendedTargetIDs,
TemplateRecordIDs, TaskRecommendationReasons, visit);
}
}
Recommendation recommendation = new Recommendation();
recommendation.ParentTaskIDs = ParentTaskIDs;
recommendation.TemplateRecordIDs = TemplateRecordIDs;
recommendation.RecommendedTargetIDs = RecommendedTargetIDs;
recommendation.TaskRecommendationReasons = TaskRecommendationReasons;
List<Recommendation> recommendations = new List<Recommendation>();
recommendations.add(recommendation);
return recommendations;
}
private static void populateTaskRecommendationsForMoreThan50PercNonCompliantKPIs(String targetID, List<String> ParentTaskIds, List<String> RecommendedTargetIDs,
List<String> TemplateRecordIDs, List<String> TaskRecommendationReasons, Visit visit) {
AssessmentTask[] promotionTasks = [SELECT Id FROM AssessmentTask WHERE ParentId = :visit.id AND TaskType = 'PromotionCheck'];
for(AssessmentTask promotionTask : promotionTasks) {
RetailVisitKpi[] retailVisitKpis = [SELECT Id, ActualIntegerValue, TargetIntegerValue,
ActualBooleanValue, TargetBooleanValue,
ActualDateTimeValue, TargetDateTimeValue,
ActualDecimalValue, TargetDecimalValue,
ActualStringValue, TargetStringValue FROM RetailVisitKpi where AssessmentTaskId= :promotionTask.Id];
Integer nonCompliantRvkpiCount = 0;
for(RetailVisitKpi retailVisitKpi : retailVisitKpis) {
if(retailVisitKpi.ActualIntegerValue != retailVisitKpi.TargetIntegerValue
|| retailVisitKpi.ActualBooleanValue != retailVisitKpi.TargetBooleanValue
|| retailVisitKpi.ActualDateTimeValue != retailVisitKpi.TargetDateTimeValue
|| retailVisitKpi.ActualDecimalValue != retailVisitKpi.TargetDecimalValue
|| retailVisitKpi.ActualStringValue != retailVisitKpi.TargetStringValue) {
nonCompliantRvkpiCount++;
}
}
if(((nonCompliantRvkpiCount/retailVisitKpis.size())*100) > 50) {
for(RetailVisitKpi retailVisitKpi : retailVisitKpis) {
if(retailVisitKpi.ActualIntegerValue != retailVisitKpi.TargetIntegerValue
|| retailVisitKpi.ActualBooleanValue != retailVisitKpi.TargetBooleanValue
|| retailVisitKpi.ActualDateTimeValue != retailVisitKpi.TargetDateTimeValue
|| retailVisitKpi.ActualDecimalValue != retailVisitKpi.TargetDecimalValue
|| retailVisitKpi.ActualStringValue != retailVisitKpi.TargetStringValue) {
ParentTaskIds.add(promotionTask.Id);
RecommendedTargetIDs.add(targetID);
TemplateRecordIDs.add(retailVisitKpi.Id);
TaskRecommendationReasons.add('More than 50% RVKPIs Non Compliant');
}
}
}
}
}
private static void populateTaskRecommendationForSurvey(String targetID, List<String> ParentTaskIds, List<String> RecommendedTargetIDs,
List<String> TemplateRecordIDs, List<String> TaskRecommendationReasons, Visit visit) {
SurveySubject[] surveySubjects = [SELECT Id FROM SurveySubject WHERE SubjectId = :visit.id LIMIT 1];
if(surveySubjects != null && surveySubjects.size() > 0) {
SurveySubject surveySubject = surveySubjects[0];
SurveyInvitation[] surveyInvitations = [SELECT Id FROM SurveyInvitation WHERE Id = :surveySubject.ParentId LIMIT 1];
if(surveyInvitations != null && surveyInvitations.size() > 0) {
AssessmentTask[] surveyTasks = [SELECT Id FROM AssessmentTask WHERE ParentId = :visit.id AND TaskType = 'ConductInStoreSurveys'];
AssessmentTask surveyTask = surveyTasks[0];
TemplateRecordIDs.add(surveyTask.Id);
ParentTaskIds.add('');
TaskRecommendationReasons.add('There is a Survey in Last Visit to the Retail Store');
RecommendedTargetIDs.add(targetID);
}
}
}
private static void populateOrderTaskRecommendationForOOSKpi(String targetID, List<String> ParentTaskIds, List<String> RecommendedTargetIDs,
List<String> TemplateRecordIDs, List<String> TaskRecommendationReasons, Visit visit) {
AssessmentTask[] assessmentTasks = [SELECT Id FROM AssessmentTask WHERE ParentId = :visit.id];
for(AssessmentTask assessmentTask : assessmentTasks) {
RetailVisitKpi[] retailVisitKpis = [SELECT Id, Type, ActualBooleanValue, VisitId FROM RetailVisitKpi where AssessmentTaskId= :assessmentTask.Id AND Type = 'OutOfStock'];
RetailVisitKpi oosRvkpi;
if(retailVisitKpis.size() > 0) {
for(RetailVisitKpi rvkpi : retailVisitKpis) {
if('OutOfStock'.equals(rvkpi.Type) && (rvkpi.ActualBooleanValue == 'true' || rvkpi.ActualBooleanValue == null)) {
oosRvkpi = rvkpi;
break;
}
}
Visit[] visitForOOSKpisTask = [SELECT Id, PlaceId FROM Visit WHERE Id = :oosRvkpi.VisitId LIMIT 1];
Visit visitForOOSTask = visitForOOSKpisTask[0];
RetailStore retailStore = [SELECT Id FROM RetailStore WHERE Id = :visitForOOSTask.PlaceId];
AssessmentTaskOrder ato = [SELECT AssessmentTaskId FROM AssessmentTaskOrder WHERE RetailStoreId = :retailStore.Id LIMIT 1];
TemplateRecordIDs.add(ato.AssessmentTaskId);
ParentTaskIds.add('');
TaskRecommendationReasons.add('Order Capture - There were OOS KPIs in Last Visit');
RecommendedTargetIDs.add(targetID);
}
}
}
}
Did this article solve your issue?
Let us know so we can improve!

