We saw how to debug our marketing automation rule in previous post. Now, let's come back to our scenario first.
We have our rule, so we are able to filter contacts who visit a movie more than X time. The missing part is sending those movies to an external service. In addition, we need to keep somehow how many times a movie has been sent to service. To do this, I am going to create a custom activity which provides us to send movies and a custom facet which keeps the count we sent.
I am not going to show how to create custom facet, I've already showed it in the beginning post of this series. I created a facet called MoviesSentToExpressFacet that keeps a dictionary. The key is movie id and value is count. I am going to update this facet when the movies send in custom activity.
There are two parts to create a custom activity. The first part is to create back end code and the second is Angular part to build marketing automation user interface.
I created a class which implement IActivity interface.
As you see in implementation, we have a parameter called ProcessLimit. It keeps how many times a movie can be sent. We have a custom service called SendMoviesService which is responsible sending movies.
We use custom facet to get info that how many time the movies have been already sent and if it is less than the limit we update the facet.
Let's add the activity in Sitecore panel and do configurations now. Here is the my custom activity, I created it under /sitecore/system/Settings/Analytics/Marketing Automation/Activity Types/ in Sitecore.
An important note that if you don't configure an icon, you get an error message in marketing automation page.
So, you have to configure an icon. Then add configurations. I registered activity class in sc.MarketingAutomation.ActivityTypes.xml file.
Since we use a custom service, we need to configure it too. It is registered in sc.MarketingAutomation.ActivityServices.xml file.
And at last, we need to register the facets in sc.MarketingAutomation.ContactLoader.xml file. If you don't do this, you will get your facets as null in activity class.
Maybe you already noticed a line in activity class. The code to set facet.
Imagine that you have a website displaying movies. Visitors are able to see movie details and take some actions like save movie or share it.
You want to follow the visitors' activities and you want to take some marketing actions based on those activities. For example, if a contact visits a movie more than X time or she/he saves a movie, you want to send those movies to an external system. In addition, there is going to be a limit to send same movie. Such as, it will not be possible to send same movie more than 2 times.
You want to configure this as a marketing automation plan to give flexibility to your marketing managers. They should be able to add configurable rules and activities.
We have our rule, so we are able to filter contacts who visit a movie more than X time. The missing part is sending those movies to an external service. In addition, we need to keep somehow how many times a movie has been sent to service. To do this, I am going to create a custom activity which provides us to send movies and a custom facet which keeps the count we sent.
I am not going to show how to create custom facet, I've already showed it in the beginning post of this series. I created a facet called MoviesSentToExpressFacet that keeps a dictionary. The key is movie id and value is count. I am going to update this facet when the movies send in custom activity.
There are two parts to create a custom activity. The first part is to create back end code and the second is Angular part to build marketing automation user interface.
I created a class which implement IActivity interface.
public class SendMoviesToExpress : IActivity { public IActivityServices Services { get; set; } public ISendMoviesService SendMoviesService { get; set; } public int ProcessLimit { get; set; } public SendMoviesToExpress(ISendMoviesService sendMoviesService) { SendMoviesService = sendMoviesService; } public ActivityResult Invoke(IContactProcessingContext context) { Condition.Requires(context.Contact).IsNotNull(); try { var moviesSentFacet = context.Contact.GetFacet<MoviesSentToExpressFacet>() ?? new MoviesSentToExpressFacet(); var moviesNotToSend = moviesSentFacet.MoviesSent.Where(x => x.Value >= ProcessLimit).Select(x => x.Key).ToList(); var movieDetailCalculatedFacet = context.Contact.GetFacet<MovieDetailCalculatedFacet>(); if (movieDetailCalculatedFacet == null) return new SuccessMove(); var moviesToSend = movieDetailCalculatedFacet.MovieVisits.Where(x => !moviesNotToSend.Contains(x.Key)).Select(x => x.Key).ToList(); //Send Movies SendMoviesService.Process(context.Contact.Id.Value, moviesToSend); foreach (var movieId in moviesToSend) { if (moviesSentFacet.MoviesSent.ContainsKey(movieId)) { moviesSentFacet.MoviesSent[movieId]++; } else { moviesSentFacet.MoviesSent.Add(movieId, 1); } } Services.Collection.SetFacet(context.Contact, MoviesSentToExpressFacet.DefaultFacetKey, moviesSentFacet); return new SuccessMove(); } catch (Exception e) { //log do something return new SuccessMove(); } return new SuccessMove(); } }
As you see in implementation, we have a parameter called ProcessLimit. It keeps how many times a movie can be sent. We have a custom service called SendMoviesService which is responsible sending movies.
We use custom facet to get info that how many time the movies have been already sent and if it is less than the limit we update the facet.
Let's add the activity in Sitecore panel and do configurations now. Here is the my custom activity, I created it under /sitecore/system/Settings/Analytics/Marketing Automation/Activity Types/ in Sitecore.
An important note that if you don't configure an icon, you get an error message in marketing automation page.
So, you have to configure an icon. Then add configurations. I registered activity class in sc.MarketingAutomation.ActivityTypes.xml file.
<MarketingAutomation.Activity.SendMoviesToExpress> <Type>Sitecore.Xdb.MarketingAutomation.Locator.ActivityTypeRegistration, Sitecore.Xdb.MarketingAutomation</Type> <LifeTime>Singleton</LifeTime> <Options> <Id>{C61C5489-B11B-40F1-AB36-23EB044C2E69}</Id> <ImplementationType>Playground.Activities.SendMoviesToExpress, Playground</ImplementationType> </Options> </MarketingAutomation.Activity.SendMoviesToExpress>
Since we use a custom service, we need to configure it too. It is registered in sc.MarketingAutomation.ActivityServices.xml file.
<Playground.SendMoviesService> <Type>Playground.Services.Movie.SendMoviesService, Playground</Type> <As>Playground.Services.Movie.ISendMoviesService, Playground</As> <LifeTime>Transient</LifeTime> </Playground.SendMoviesService>
And at last, we need to register the facets in sc.MarketingAutomation.ContactLoader.xml file. If you don't do this, you will get your facets as null in activity class.
<MarketingAutomation.Loading.ContactFacetsConfigurator> <Type>Sitecore.Xdb.MarketingAutomation.Loading.ContactFacetsConfigurator, Sitecore.Xdb.MarketingAutomation</Type> <As>Sitecore.Xdb.MarketingAutomation.Core.Loading.IContactExpandOptionsConfigurator, Sitecore.Xdb.MarketingAutomation.Core</As> <LifeTime>Singleton</LifeTime> <Options> <IncludeFacetNames> <Facet1>MovieDetailCalculatedFacet</Facet1> <Facet2>MoviesSentToExpressFacet</Facet2> </IncludeFacetNames> <ExcludeFacetNames /> </Options> </MarketingAutomation.Loading.ContactFacetsConfigurator>
Maybe you already noticed a line in activity class. The code to set facet.
Services.Collection.SetFacet(context.Contact, MoviesSentToExpressFacet.DefaultFacetKey, moviesSentFacet);
Sitecore provides preregistered services in activity class by implementing IActivity interface. Normally, how do you set a facet? If you read documentation, you can think that you need to use xconnect client api. But here, there is a limitation that you don't have access to xconnect. After I got error and some investigation, I noticed that Sitecore already provides a service to do this. It could be useful for you to have a look at preregistered services based on your needs.
And that's it! Everything is ready to work on back end part, now it is time to configure UI with Angular.
Let's do that in part 2.
This is such a great resource that you providing and you give it away for free. I love seeing websites that understand the value of providing a quality resource for free. It is the old what goes around comes around routine.marketing
ReplyDeleteVery Informative! To know more on sitecore course
ReplyDelete