Loading
Impostazione e gestione di Retail Execution
Sommario
Seleziona filtri

          Nessun risultato
          Nessun risultato
          Ecco alcuni suggerimenti per la ricerca

          Controlla l'ortografia delle parole chiave.
          Usa termini di ricerca più generici.
          Seleziona meno filtri per ampliare la tua ricerca.

          Cerca in tutta la Guida di Salesforce
          Come consigliare visite tramite Apex

          Come consigliare visite tramite Apex

          È possibile creare una classe Apex per definire un elenco di punti di vendita al dettaglio specifici per i quali Einstein dovrà fornire consigli visita. Quindi è possibile creare un flusso e aggiungere la Classe Apex come elemento Azione.

          Versioni (Edition) richieste

          Disponibile in Lightning Experience in Professional Edition, Unlimited Edition ed Enterprise Edition con Consumer Goods Cloud abilitato.
          Importante
          Importante Per utilizzare un'azione Apex in un flusso, richiedere allo sviluppatore di annotare il metodo appropriato con @InvocableMethod.

          Di seguito è visualizzato un esempio di classe Apex per filtrare i punti vendita:

          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;
            }
          
          }
           
          Caricamento
          Salesforce Help | Article