How to create custom order flows for the Order Website.
Overview
The order flow relies on mapping named routes in the route configuration and then putting them together into one or more order flows.
Configuration of the order flow happens in MyTheme\App_Start\OrderFlowConfig.cs
and route configuration in MyTheme\App_Start\RouteConfig.cs
.
The following controller/action pairs are currently possible to use as part of an order flow:
- Domains/Index
- ProductListing/Index
- Account/Index
- Checkout/Index
All routes which should be part of an order flow must be mapped with the RouteCollection
extension method MapOrderFlowRoute
.
All order flows must have a name. This name is used when deciding what order flow is currently applicable. You can also specify one order flow as the default order flow. The resolution order of what order flow to use is the following:
- If there is a query string
?flow={orderFlowName}
and there exists an order flow with that name, use that order flow. - Use any existing order flow with the same name as the application hostname, e.g. store.example.com.
- Use the default order flow.
Re-ordering Existing Order Flow Steps
The Default theme has a single default order flow named DefaultFlow that contains the following steps: Domains => HostingPackage => Account => Checkout.
As mentioned above, the Account and Checkout steps should always be located in the last two steps of the order flow. So for re-ordering the existing DefaultFlow order flow the only realistic option left is to switch places between Domains and HostingPackage.
Start by configuring the the new order flow in MyTheme\App_Start\OrderFlowConfig.cs
. The final configuration will look something like this (with each step explained below):
public static void RegisterOrderFlows(OrderFlowCollection orderFlows) { // 1. orderFlows.Clear(); // 2. var orderFlow = new OrderFlow("MyOrderFlow", new [] {"HostingPackage", "Domains", "Account", "Checkout"}); // 3. orderFlow.AddRouteNameAlias("OrderFlowStart", "HostingPackage"); // 4. orderFlows.Add(orderFlow, true); }
- To re-order the one order flow which you have, completely remove it from the existing order flows.
- Define the new order flow MyOrderFlow with HostingPackage placed before Domains.
- Add an alias from the OrderFlowStart route to HostingPackage (see more below) to have the first step in the order flow accessible at the root path of the application.
- Add MyOrderFlow to the order flows used by the application and set it as default.
- In step 3 above, you added an alias from the OrderFlowStart route to HostingPackage. However, in the default route config the OrderFlowStart route is set to resolve to Domains, so you also have to add a change to
MyTheme\App_Start\RouteConfig.cs
:public static void RegisterRoutes(RouteCollection routes) { // 1. routes.Remove(routes["OrderFlowStart"]); // 2. routes.MapOrderFlowRoute( name: "OrderFlowStart", url: "", defaults: new { controller = "ProductListing", action = "Index", query = "HostingPackage", viewName = "HostingPackage" } ); }
- Remove the original OrderFlowStart route.
- Define the new OrderFlowStart route with the same defaults as the HostingPackage route, but with a new
url
value to match the root URL of the application.
Adding a New Order Flow Step
Continuing with the example from Re-ordering Existing Order Flow Steps we might want to add a page offering extra services as the final step before Account and Checkout. This will add a new route to a page listing the extra services and add that route to the order flow.
- Start by adding the following route to the route configuration:
routes.MapOrderFlowRoute( name: "ExtraService", url: "Addons", defaults: new { controller = "ProductListing", action = "Index", query = "ExtraService", viewName = "ExtraService" } );
- Note the following about the route configuration options:
- name: The route is named
ExtraService
, which is also the name which must be used in the order flow configuration. - url: How the route is represented to the end user is not dependent on the route name so in this example we chose
/Addons
instead. - controller and action: These are pages for listing products.
- query: By default the
ProductListing.Index
action list’s products with the category specified inquery
. - viewName: If you want to implement a different view for this page you must add the
Themes\MyTheme\Views\ProductListing\ExtraService.cshtml
later since it is not part of theDefault
theme. You should also add new resource translations for the step title and description (see Changing the Order Flow Presentation).
- name: The route is named
- Add the new page to the order flow:
var orderFlow = new OrderFlow("MyOrderFlow", new [] {"HostingPackage", "Domains", "ExtraService", "Account", "Checkout"});
Creating Multiple Domain Based Order Flows
It is possible to create multiple order flows in AtomiaStore and also to connect them to the hostname of the application. E.g. you might want to have two different order flows for selling shared hosting and VPS located at hosting.store.example.com and vps.store.example.com respectively. Assuming that Atomia Billing has been set up for this and that the routes have been added you could configure the order flows as follows:
public static void RegisterOrderFlows(OrderFlowCollection orderFlows) { orderFlows.Clear(); var sharedHostingFlow = new OrderFlow("hosting.store.example.com", new[] { "Domains", "HostingPackage", "Account", "Checkout" }); sharedHostingFlow.AddRouteNameAlias("OrderFlowStart", "Domains"); var vpsFlow = new OrderFlow("vps.store.example.com", new[] { "Domains", "VPS", "Account", "Checkout" }); vpsFlow.AddRouteNameAlias("OrderFlowStart", "Domains"); orderFlows.Add(sharedHostingFlow, true); orderFlows.Add(vpsFlow); }
Note the following regarding this configuration:
- If you want to have a single entry point for the two order flows, e.g. the Domains page, and then let the customer choose what flow to continue with you must yourself manually set up the links to the next step in the respective order flow (see Changing the Order Flow Presentation below).
- The hosting.store.example.com flow is set as default, so if you for example also have store.example.com available the customers that enter from there will get the shared hosting flow. You can also choose to not have a default order flow.
- If you for some reason want to switch order flow but keep the customer at the same domain you could do it by adding the
?flow={orderFlowName}
query string with the name of the other order flow as orderFlowName.
Changing the Order Flow Presentation
Views that are part of the order flow have access to order flow data of the type Atomia.Store.AspNetMvc.Models.OrderFlowModel
via ViewBag.OrderFlow
.
The Default theme uses this data in the step specific _Actions.cshtml
partial views to render buttons to move between steps and uses the shared partial view _Progress.cshtml
to present the order flow progress.
Each order flow step has the following properties:
- Title
- Description
- StepNumber
- Previous
- Next
Title
and Description
are populated by resource strings from App_GlobalResources\Common.*.resx
with names on the form StepTitle{Name} and StepDescription{Name}. StepNumber
is the 1-based index of the step in the order flow.
The steps also have the Previous
and Next
properties, which are the names of the previous and next steps in the order flow. If the value of either property is an empty string it means that there is no step in that direction, e.g. Checkout always has an empty Next
property.
The Previous
and Next
properties match named routes so they can be used e.g. with the RouteLink
HTML-helper to render links to another step.
@Html.RouteLink(Html.CommonResource("Back"), orderFlow.CurrentStep.Previous, new { flow = orderFlow.Name }, new { id = "back_step" })
The above example renders a link to the previous step and also sets the flow
query string to the value from orderFlow.Name
.
Validating the Order Flow Steps
The steps in an order flow can be validated by implementing the Atomia.Store.AspNetMvc.Ports.IOrderFlowValidator
interface.
The ValidateOrderFlowStep
method gets called for the current step, and if the step is not valid there is an automatic redirect to the previous step.
The purpose of this is to prevent users from going directly to an order flow step that does not make sense.
There is a default implementation in Atomia.Store.Themes.Default.Adapters.OrderFlowValidator
that checks that the cart is not empty in the Account step. It also checks that the cart is not empty and that contact data is not empty in the Checkout step.