Skip to content

Instantly share code, notes, and snippets.

@davidknipe
Last active May 27, 2021 10:59
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save davidknipe/51003f9084c85d82dc08f75be2b4a41f to your computer and use it in GitHub Desktop.
Starter code to send order confirmation events to Optimizely Data Platform
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Web;
using EPiServer.Commerce.Order;
using EPiServer.Framework;
using EPiServer.Framework.Initialization;
using EPiServer.ServiceLocation;
// Note all in a single gist for convienience
namespace Foundation.Features.OdpOrderConfirmation
{
[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class OdpOrderConfirmationTrackingInit : IInitializableModule
{
private static readonly HttpClient httpClient = new HttpClient();
private static OdpConfigOptions _configOptions;
public void Initialize(InitializationEngine context)
{
_configOptions = context.Locate.Advanced.GetInstance<OdpConfigOptions>();
var orderEvents = context.Locate.Advanced.GetInstance<IOrderEvents>();
orderEvents.SavingOrder += OrderEvents_SavingOrder;
orderEvents.SavedOrder += OrderEvents_SavedOrder;
}
private void OrderEvents_SavingOrder(object sender, OrderEventArgs e)
{
var orderType = e.OrderLink.OrderType.Name;
HttpContext.Current.Items["orderType"] = orderType;
}
private void OrderEvents_SavedOrder(object sender, OrderEventArgs e)
{
var orderType = e.OrderLink.OrderType.Name;
// The order group has become PO so assume we are transitioning from basket to PO
if (HttpContext.Current != null &&
HttpContext.Current.Items["orderType"].ToString() != orderType &&
orderType == "PurchaseOrder")
{
PostOrderConfirm(e.OrderGroup);
}
}
public void Uninitialize(InitializationEngine context)
{
var orderEvents = context.Locate.Advanced.GetInstance<IOrderEvents>();
orderEvents.SavingOrder -= OrderEvents_SavingOrder;
orderEvents.SavedOrder -= OrderEvents_SavedOrder;
}
private bool PostOrderConfirm(IOrderGroup orderGroup)
{
// Use the id stored in the vuid cookie to identify the visitor
var customerId = HttpContext.Current.Request.Cookies["vuid"]?.Value.Split('%')[0].Replace("-", string.Empty);
var orderNo = ((Mediachase.Commerce.Orders.PurchaseOrder)orderGroup).TrackingNumber;
var orderTotal = orderGroup.GetTotal().ToString("0.00");
var orderSubtotal = orderGroup.GetSubTotal().ToString("0.00");
var orderTax = orderGroup.GetTaxTotal().ToString("0.00");
var orderShipping = orderGroup.GetShippingTotal().ToString("0.00");
var orderDiscount = orderGroup.GetOrderDiscountTotal().ToString("0.00");
var payload = new Payload()
{
type = "order",
action = "purchase",
identifiers = new Identifiers()
{
vuid = customerId
},
data = new Data()
{
order = new Order()
{
order_id = orderNo,
total = orderTotal,
coupon_code = null,
discount = orderDiscount,
shipping = orderShipping,
subtotal = orderSubtotal,
tax = orderTax,
items = new List<Item>()
}
}
};
foreach (var lineItem in orderGroup.GetAllLineItems())
{
var lineItemProductId = lineItem.Code;
var lineItemPrice = lineItem.PlacedPrice.ToString("0.00");
var lineItemQuantity = Convert.ToInt32(lineItem.Quantity);
var lineItemDiscount = lineItem.GetEntryDiscount().ToString("0.00");
var lineItemSubtotal = (
(lineItem.PlacedPrice * lineItem.Quantity) - lineItem.GetEntryDiscount()).ToString("0.00");
payload.data.order.items.Add(new Item()
{
discount = lineItemDiscount,
price = lineItemPrice,
product_id = lineItemProductId,
quantity = lineItemQuantity,
subtotal = lineItemSubtotal
}
);
}
string payloadJson = Mediachase.Web.Console.Common.JsonSerializer.Serialize(payload);
var content = new StringContent(payloadJson, Encoding.UTF8, "application/json");
content.Headers.ContentType.MediaType = "application/json";
content.Headers.Add("x-api-key", _configOptions.EventsApiKey);
var response = httpClient.PostAsync(_configOptions.EventsApiUrl, content).Result;
return response.IsSuccessStatusCode;
}
}
/// <summary>
/// Optimizely Data Platform config options
/// </summary>
/// <remarks>
/// Using an [Options] class means these values can be set through code or config. To see how to set through
/// config see this: https://world.episerver.com/documentation/Release-Notes/ReleaseNote/?releaseNoteId=CMS-15875
/// </remarks>
[Options]
public class OdpConfigOptions
{
public string EventsApiUrl { get; set; }
public string EventsApiKey { get; set; }
public OdpConfigOptions()
{
EventsApiUrl = "https://api.zaius.com/v3/events";
EventsApiKey = "[ODP API KEY LIVES HERE]";
}
}
public class Data
{
public Order order { get; set; }
}
public class Identifiers
{
public string vuid { get; set; }
}
public class Item
{
public string product_id { get; set; }
public string price { get; set; }
public int quantity { get; set; }
public string discount { get; set; }
public string subtotal { get; set; }
}
public class Order
{
public string order_id { get; set; }
public string total { get; set; }
public string discount { get; set; }
public string subtotal { get; set; }
public string tax { get; set; }
public string shipping { get; set; }
public string coupon_code { get; set; }
public List<Item> items { get; set; }
}
public class Payload
{
public string type { get; set; }
public string action { get; set; }
public Identifiers identifiers { get; set; }
public Data data { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment