您位於此處:
使用 Apex 建議造訪
對 Einstein 必須提供造訪建議的特定商店清單建立 Apex 類別。然後您便可以建立流程,並將 Apex 類別作為「動作」元素新增。
必要版本
| 適用於已啟用 Consumer Goods Cloud 的 Lightning Experience Professional、Unlimited 和 Enterprise Edition。 |
重要 若要在策略中使用 Apex 動作,請您的開發人員以 @InvocableMethod 註解適當的方法。
用於篩選商店的 Apex 類別如下所示:
global class BulkGetVisitRecommendations {
@InvocableMethod(label='Bulk Get Visit Recommendations from Apex')
global static List<Recommendation> getRecommendations(List<List<String>> inputList) {
List<Recommendation> recommendations = new List<Recommendation>();
if(inputList != null && inputList.size() > 0 ){
Recommendation recommendation = new Recommendation();
List<String> recommendedStoreIds = new List<String>();
List<String> reasonForRecommendations = new List<String>();
List<String> input = inputList.get(0);
//Last element in input is DateString
Date visitRecommendationTargetDate = Date.valueof(input.get(input.size()-1));
populateRecommendationsBasedOnCases(input,recommendedStoreIds,reasonForRecommendations);
populateRecommendationsBasedOnPromotions(input,visitRecommendationTargetDate,recommendedStoreIds,reasonForRecommendations);
populateRecommendationsBasedOnOutOfStockKPIs(input,visitRecommendationTargetDate,recommendedStoreIds,reasonForRecommendations);
recommendation.StoreIds = recommendedStoreIds;
recommendation.RecommendationReasons = reasonForRecommendations;
recommendations.add(recommendation);
}
return recommendations;
}
public static void populateRecommendationsBasedOnCases(List<String> storeIds,List<String> recommendedStoreIds,List<String> reasonForRecommendations) {
List<RetailStore> stores = [select Id, PrimaryContactId from RetailStore where Id IN :storeIds AND PrimaryContactId != null];
if(stores!=null){
//Check for open cases agianst primarycontact of store.
//System.debug('stores found ');
Map<String, String> StoreToprimaryContactMap = new Map<String,String>();
if(stores.size() > 0){
for(RetailStore store : stores){
StoreToPrimaryContactMap.put(store.Id,store.PrimaryContactId);
}
List<AggregateResult> casesForPrimaryContactOfStores = [Select contactId, max(createdDate) from Case where isClosed = false AND contactid in :StoreToPrimaryContactMap.values() group by contactId];
Map<String, DateTime> primaryContactToCaseCreationDateTimeMap = new Map<String,DateTime>();
if(casesForPrimaryContactOfStores != null && casesForPrimaryContactOfStores.size() > 0){
for(AggregateResult caseResult : casesForPrimaryContactOfStores){
Date caseDate = Date.valueOf(caseResult.get('expr0'));
DateTime caseDateTime = DateTime.newInstance(caseDate.year(),caseDate.month(),caseDate.day(),0,0,0);
primaryContactToCaseCreationDateTimeMap.put(String.valueof(caseResult.get('ContactId')),caseDateTime);
}
}
//Get latest Visit for PlaceId
List< AggregateResult > latestVisitsForStores = [Select PlaceId, max(PlannedVisitStartTime) FROM Visit where PlaceId in :StoreToPrimaryContactMap.keyset() group by PlaceId];
if(latestVisitsForStores !=null && latestVisitsForStores.size() > 0){
for(AggregateResult visit : latestVisitsForStores){
String storeId = String.valueof(visit.get('PlaceId'));
String primaryContactId = StoreToprimaryContactMap.get(storeId);
//System.debug('primaryContactId found '+primaryContactId+' latest Visit Date for store '+storeId+' is '+visit.get('expr0'));
DateTime caseCreationDateTime = primaryContactToCaseCreationDateTimeMap.get(primaryContactId);
if(DateTime.valueof(visit.get('expr0')) < caseCreationDateTime){
// No visit is created after case is in open state.
reasonForRecommendations.add('No visit created after the latest case logged against primary contact');
recommendedStoreIds.add(storeId);
}
}
}
}
}else{
System.debug('PrimaryContact is empty for all stores');
}
}
public static void populateRecommendationsBasedOnPromotions(List<String> storeIds, Date visitRecommendationTargetDate, List<String> recommendedStoreIds,List<String> reasonForRecommendations) {
Integer noOfDaysToConsiderPromotion = 7;
Date promoStartDate = visitRecommendationTargetDate.addDays(noOfDaysToConsiderPromotion);
Date promoEndDate = visitRecommendationTargetDate.addDays(365);
List<PromotionChannel> promotionchannels = [Select Id, RetailStoreId from PromotionChannel where RetailStoreId IN :storeIds AND startDate > :promoStartDate AND (endDate < :promoEndDate OR endDate = null)];
if(promotionchannels != null){
for(PromotionChannel promotionChannel : promotionchannels){
//upcoming promotion for store
//System.debug('promotionchannels for storeId - ' + promotionChannel.RetailStoreId+' is '+promotionchannel);
reasonForRecommendations.add('Upcoming Promotion for the store scheduled after '+noOfDaysToConsiderPromotion +' days');
recommendedStoreIds.add(promotionChannel.RetailStoreId);
}
}
}
public static void populateRecommendationsBasedOnOutOfStockKPIs(List<String> storeIds,Date visitRecommendationTargetDate,List<String> recommendedStoreIds,List<String> reasonForRecommendations) {
Integer noOfVisitRecordsForStore = 5;
Integer noofDaysStoreNotVisited = 14;
Date actualVisitStartDateForStoreNotVisited = visitRecommendationTargetDate.addDays(-noofDaysStoreNotVisited);
DateTime actualVisitStartDateTimeForStoreNotVisited = DateTime.newInstance(actualVisitStartDateForStoreNotVisited.year(),actualVisitStartDateForStoreNotVisited.month(),actualVisitStartDateForStoreNotVisited.day(),0,0,0);
Integer noOfVisitsToCheckForOOS = 1;
String outOfStock = 'OutOfStock';
List<Visit> visitsExecuted = [SELECT Id,PlaceId FROM Visit WHERE PlaceId IN :storeIds AND ActualVisitStartTime != null AND ActualVisitStartTime > :actualVisitStartDateTimeForStoreNotVisited];
List<String> storeIdsCopy = storeIds;
if(visitsExecuted!= null && visitsExecuted.size() > 0){
// visit is already executed for the stores
for (Visit visit : visitsExecuted) {
Integer index =storeIdsCopy.indexOf(visit.PlaceId);
if(index != -1)
storeIdsCopy.remove(index);
}
}
//System.debug('Visit is not executed for '+storeIdsCopy.size()+' stores');
Map<String,String> visitIdToStoreIdMap = new Map<String,String>();
List<String> filteredVisitIdsToCheckOutOfStockKPIS = new List<String>();
Map<String, List<String>> storeIdToVisits = new Map<String,List<String>>();
List<Visit> visits = [SELECT Id,PlaceId FROM Visit WHERE PlaceId IN :storeIdsCopy AND ActualVisitStartTime != null ORDER BY ActualVisitStartTime];
for (Visit visit : visits) {
String storeId = visit.PlaceId;
visitIdToStoreIdMap.put(visit.Id,storeId);
if (storeIdToVisits.get(storeId) == null){
List<String> newList = new List<String>();
newList.add(visit.Id);
storeIdToVisits.put(storeId, newList);
filteredVisitIdsToCheckOutOfStockKPIS.add(visit.Id);
}else{
// add visit id for store only if no. of visits for each store is less than configured #noOfVisitRecordsForStore
if(storeIdToVisits.get(storeId).size() <= noOfVisitRecordsForStore){
storeIdToVisits.get(storeId).add(visit.Id);
filteredVisitIdsToCheckOutOfStockKPIS.add(visit.Id);
}
}
}
Map<String,Integer> storeIdToOosKPICount = new Map<String,Integer>();
List<RetailVisitKpi> oosRetailVisitkpis= [SELECT Id, Assessmenttask.parentid FROM RetailVisitKpi WHERE Assessmenttask.parentid IN :filteredVisitIdsToCheckOutOfStockKPIS AND Type = :outOfStock AND TargetBooleanValue = 'True'];
for (RetailVisitKpi rvkpi : oosRetailVisitkpis) {
String visitId = rvkpi.Assessmenttask.parentid;
String storeId = visitIdToStoreIdMap.get(visitId);
Integer currentStoreIdOOSKPICount = storeIdToOosKPICount.get(storeId);
if(currentStoreIdOOSKPICount == null){
storeIdToOosKPICount.put(storeId,1);
}else{
Integer newStoreIdOOSKPICount = currentStoreIdOOSKPICount+1;
storeIdToOosKPICount.put(storeId,newStoreIdOOSKPICount);
//System.debug('OOS KPI count for '+storeId+' is '+newStoreIdOOSKPICount);
}
if(storeIdToOosKPICount.get(storeId) == noOfVisitsToCheckForOOS){
reasonForRecommendations.add('Store is not visited in last '+noofDaysStoreNotVisited + ' days and there are atleast '+noOfVisitsToCheckForOOS+ ' Out of stock kpis in previous visits');
recommendedStoreIds.add(storeId);
}
}
}
global class Recommendation {
@InvocableVariable
global List<String> StoreIds;
@InvocableVariable
global List<String> RecommendationReasons;
}
}此文章是否解決您的問題?
請讓我們知道,以便我們改進!

