Customize order processing activity flows
Describes the customization of activity flows for order processing in Optimizely Commerce Connect 13.
To replace or customize an activity flow:
- In a Visual Studio project, create and build a new activity flow.
- Add existing or new activities to it.
Classes in this topic are available in the following namespaces:
- Mediachase.Commerce.Workflow. Contains the workflows.
- Mediachase.Commerce.Workflow.Activities.Cart. Contains the activities.
Configuration
Configure the activity flows in a .CS file (the config file \Configs\ecf.workflow.config is no longer needed).
An activity flow should inherit from the ActivityFlow class. You can decorate it with an ActivityFlowConfiguration attribute.
[ActivityFlowConfiguration(Name = “Example”)]
public class ExampleActivityFlow : ActivityFlow
Each activity flow should have a unique name. If the Name parameter is not provided, the engine gets the ActivityFlow class name. In this example, Name is ExampleActivityFlow. The activity flow name is used to look up and execute.
Example: ExecutionManager.ExecuteActivityFlow(workflowName, parameters)
An activity flow should implement a Configure method to declare which activities are executed, and how they are executed. You can configure an activity flow to override another flow of the same name and mode by setting a higher priority. The default priority is zero (0). For example, you configure two flows with the same name and all in beta mode:
[ActivityFlowConfiguration(Name = “Example”)]
public class BetaExampleActivityFlow : ActivityFlow
[ActivityFlowConfiguration(Name = “Example”, Priority = 1)]
public class AlphaExampleActivityFlow : ActivityFlow
When the activity flow "Example" is called in beta mode, it creates an instance of AlphaExampleActivityFlow class, not BetaExampleActivityFlow. This means that only the AlphaExampleActivityFlow is registered for the "Example" activity flow.
Note
You can register a workflow without the ActivityFlowConfiguration attribute. If a workflow is inherited from the ActivityFlow class and not decorated by the attribute, it is still registered with same name as the name of class.
Create an activity to send notifications
The following example creates a new workflow activity, then uses it in a new workflow. It uses this workflow to replace the shipped CartCheckout workflow. The new activity sends an automated email to store customers after an order completion. This example illustrates how to update and customize a flow.
Create an activity
- Create a Workflow Activity Library project in Visual Studio. In this example, we named the project CustomActivityLibrary1.
- Add a new activity to the activities project for the email. Name the activity SendNotification.
- Set the inheritance for the activity to Mediachase.Commerce.WorkflowCompatibility.Activity.
- Make sure you installed the EPiServer.Commerce.Core NuGet package.
- Add the code to the new activity's code-behind file (SendNotification.cs) from the Code Sample section in this document. Ensure the naming is correct, that you create the stub of the method to send the email, and that your method is called in the activity's Execute method. A stub for the method is provided in the SendEmailNotification() method. See the SendEmails method code in the /Templates/Everything/BusinessControls/CheckoutControls/CheckoutWizardModule.cs file.
Note
Use the activity OrderGroup object reference to retrieve the information about the order to be put in the email. To generate the formatted copy of the email body text with the order information, use the Mediachase.Commerce.Engine.Template.TemplateService. See sending Order notifications for information about the template service.
- Build the project.
Add activity to activity flow
Add the activity created above (along with other activities contained in the Mediachase.Commerce.Workflow.dll) to a new activity flow. Use this activity flow to replace the CartCheckoutActivityFlow (Mediachase.Commerce.Workflow.CartCheckoutActivityFlow).
- Create a Activity Flow project in Visual Studio. In this example, name the project MyCustomCartCheckout.
- Make sure you installed EPiServer.Commerce.Core NuGet package.
- Add a class to the customCartCheckout project. In this example, name it CustomCartCheckout. Set the inheritance for the activity flow to Mediachase.Commerce.Engine.ActivityFlow. And decorate the class with ActivityFlowConfiguration attribute. By setting the Name as CartCheckout, you override the default implementation of Mediachase.Commerce.Workflow.CartCheckoutActivityFlow.
- In the activity flow file (in this example named CustomCartCheckout.cs), implement the Configure method to configure the list of activities to be executed, and add the last step to use the SendNotification activity. See the relevant code in the code sample section in this document.
- Build the project.
- Locate the newly-built assembly and copy it to the project's bin folder.
- Recompile, and access the website where this activity is used during checkout.
Examples
Example: starting code for the SendNotification activity
using Mediachase.Commerce.Engine;
using Mediachase.Commerce.Orders;
using Mediachase.Commerce.WorkflowCompatibility;
using System;
namespace CustomActivity
{
public partial class SendNotification : Activity
{
/// <summary>
/// Gets or sets the order group.
/// </summary>
/// <returns>The order group.</returns>
[ActivityFlowContextProperty]
public OrderGroup OrderGroup { get; set; }
/// <summary>
/// Called by the workflow runtime to execute an activity.
/// </summary>
/// <param name="executionContext">The <see cref="T:Mediachase.Commerce.WorkflowCompatibility.ActivityExecutionContext"/> to associate with this <see cref="T:Mediachase.Commerce.WorkflowCompatibility.Activity"/> and execution.</param>
/// <returns>
/// The of the run task, which determines whether the activity remains in the executing state, or transitions to the closed state.
/// </returns>
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
try
{
// Validate the properties at runtime
this.ValidateRuntime();
//Send notification
this.SendEmailNotification();
// Retun the closed status indicating that this activity is complete.
return ActivityExecutionStatus.Closed;
}
catch
{
// An unhandled exception occured. Throw it back to the WorkflowRuntime.
throw;
}
}
/// <summary>
/// Calculates the sale taxes.
/// </summary>
private void SendEmailNotification()
{
//provide implementation here
}
/// <summary>
/// Validates the runtime.
/// </summary>
private bool ValidateRuntime()
{
// Create a new collection for storing the validation errors
ValidationErrorCollection validationErrors = new ValidationErrorCollection();
// Validate the Order Properties
this.ValidateOrderProperties(validationErrors);
// Raise an exception if we have ValidationErrors
if (validationErrors.HasErrors)
{
string validationErrorsMessage = String.Empty;
foreach (ValidationError error in validationErrors)
{
validationErrorsMessage +=
string.Format("Validation Error: Number {0} - '{1}' \n",
error.ErrorNumber, error.ErrorText);
}
// Throw a new exception with the validation errors.
throw new WorkflowValidationFailedException(validationErrorsMessage, validationErrors);
}
// If we made it this far, then the data must be valid.
return true;
}
private void ValidateOrderProperties(ValidationErrorCollection validationErrors)
{
// Validate the To property
if (this.OrderGroup == null)
{
ValidationError validationError = ValidationError.GetNotSetValidationError("OrderGroup");
validationErrors.Add(validationError);
}
}
}
}
Example: CustomCartCheckout.cs
using Mediachase.Commerce.Engine;
using Mediachase.Commerce.Workflow.Activities;
using Mediachase.Commerce.Workflow.Activities.Cart;
namespace CustomActivity
{
[ActivityFlowConfiguration(Name = "CartCheckout")]
public class CustomCartCheckout : ActivityFlow
{
public override ActivityFlowRunner Configure(ActivityFlowRunner runner)
{
return runner.If(() => ShouldProcessPayment())
.Do<ProcessPaymentActivity>()
.EndIf()
.Do<CalculateTotalsActivity>()
.Do<AdjustInventoryActivity>()
.Do<RecordPromotionUsageActivity>()
.Do<SendNotification>();
}
}
}
Updated 2 months ago